From 1a9cb7abdc11e58fe16416e32b1f4ce8978b783f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 30 Apr 2024 11:07:31 +0200 Subject: [PATCH 001/287] intermediate status for Anna --- Images/qiita/Dockerfile | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Images/qiita/Dockerfile diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile new file mode 100644 index 0000000..988b3ba --- /dev/null +++ b/Images/qiita/Dockerfile @@ -0,0 +1,40 @@ +FROM ubuntu:22.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y install \ + git \ + wget + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ + conda init + +# create conda env for qiita with all necessary dependencies (conda and pip) +RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy nginx cython anaconda::redis + +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-n", "qiita", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN pip install \ + sphinx \ + sphinx-bootstrap-theme \ + nose-timer \ + Click \ + coverage + +#RUN mkdir Git +#RUN git clone -b dev https://github.com/qiita-spots/qiita.git + + +#https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh From 85933eba2c6694c77e8ed8c342774792163e06f6 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 16 May 2024 14:13:03 +0200 Subject: [PATCH 002/287] Bash file including commands to execute upon container start --- Images/qiita/start_qiita.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Images/qiita/start_qiita.sh diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh new file mode 100644 index 0000000..bad4c42 --- /dev/null +++ b/Images/qiita/start_qiita.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +#first we start the redis server +redis-server --daemonize yes --port 7777 +redis-server --daemonize yes --port 6379 + +#building the database without ontologies +qiita-env make --no-load-ontologies + +#starting the webserver without building the docs +qiita pet webserver --no-build-docs start \ No newline at end of file From b05fdae3aeb9d3d1faedadeec9fa15f94db78734 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 16 May 2024 14:14:06 +0200 Subject: [PATCH 003/287] Add qiita env/init files based on previous example --- environments/qiita-db-init.sh | 8 ++++++++ environments/qiita.env | 3 +++ environments/qiita_db.env | 1 + 3 files changed, 12 insertions(+) create mode 100644 environments/qiita-db-init.sh create mode 100644 environments/qiita.env create mode 100644 environments/qiita_db.env diff --git a/environments/qiita-db-init.sh b/environments/qiita-db-init.sh new file mode 100644 index 0000000..97729bf --- /dev/null +++ b/environments/qiita-db-init.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -e +set -u + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" "$POSTGRES_DB" <<-EOSQL + ALTER DATABASE "$POSTGRES_DB_NAME" OWNER TO "$POSTGRES_USER" +EOSQL diff --git a/environments/qiita.env b/environments/qiita.env new file mode 100644 index 0000000..ddadb4e --- /dev/null +++ b/environments/qiita.env @@ -0,0 +1,3 @@ +QIITA_ROOTCA_CERT=`pwd`/qiita_core/support_files/ci_rootca.crt +QIITA_CONFIG_FP=`pwd`/qiita_core/support_files/config_test.cfg + diff --git a/environments/qiita_db.env b/environments/qiita_db.env new file mode 100644 index 0000000..af9fa55 --- /dev/null +++ b/environments/qiita_db.env @@ -0,0 +1 @@ +POSTGRES_PASSWORD=postgres From 40f213aeb9770053e5176ce95c1c3503fd861fb8 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 16 May 2024 14:14:58 +0200 Subject: [PATCH 004/287] Add Dockerfile to build Qiita image --- Images/qiita/Dockerfile | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 988b3ba..6ad1f9e 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -9,7 +9,7 @@ RUN apt-get -y update RUN apt-get -y install \ git \ wget - +RUN apt-get -y install build-essential # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ @@ -33,8 +33,34 @@ RUN pip install \ Click \ coverage -#RUN mkdir Git -#RUN git clone -b dev https://github.com/qiita-spots/qiita.git +#Clone the Qiita Repo +RUN git clone -b master https://github.com/qiita-spots/qiita.git + + +#We need to install necessary dependencies +#as well as some extra dependencies for psycopg2 to work +RUN git clone https://github.com/psycopg/psycopg2.git +RUN apt-get -y update +RUN apt-get -y install libpq-dev python3-dev gcc +RUN pg_config --version +RUN export PATH=/usr/lib/postgresql/14.11/bin/:$PATH +RUN pip install psycopg2-binary +RUN pip install -e psycopg2/. + +#Install pip packaages for Qiita +RUN pip install -e qiita/. --no-binary redbiom +RUN pip install "Jinja2<3.1" + + +#Configuring the Qiita Config to run inside the container +RUN sed -i 's/BASE_URL = https:\/\/localhost:8383/BASE_URL = https:\/\/localhost:21174\//' qiita/qiita_core/support_files/config_test.cfg +RUN sed -i 's/\/home\/runner\/work\/qiita\/qiita\//\/qiita\//' qiita/qiita_core/support_files/config_test.cfg +#Copy Bash Script to run Qiita to the container +COPY start_qiita.sh . +RUN chmod 777 start_qiita.sh -#https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh +#I will leave this ENTRYPOINT here as a comment in case debugging +#is necessary +#ENTRYPOINT ["/bin/bash"] +ENTRYPOINT ["conda", "run", "-n", "qiita", "./start_qiita.sh"] \ No newline at end of file From a5024e52b74e69bbeecbcf91f0ccd993106d4779 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 16 May 2024 14:16:37 +0200 Subject: [PATCH 005/287] Change compose file to fit Qiita deployment, keep compose file from keycloak branch as keycloak_compose.yaml --- compose.yaml | 61 ++++++++++++++++++------------------------- keycloak_compose.yaml | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 36 deletions(-) create mode 100644 keycloak_compose.yaml diff --git a/compose.yaml b/compose.yaml index e581619..4baea57 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,52 +1,41 @@ -version: '3' - services: - keycloak-db: + qiita-db: image: postgres:15 - container_name: keycloak-db - hostname: keycloak-db - restart: unless-stopped + container_name: qiita-db + hostname: qiita-db + network_mode: host + restart: no env_file: - - ./environments/db.env + - ./environments/qiita_db.env environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - - KEYCLOAK_DB_NAME=keycloak - - KEYCLOAK_DB_USER=keycloak + - POSTGRES_DB_NAME=postgres + - POSTGRES_DB_USER=postgres volumes: - - './environments/db-init.sh:/docker-entrypoint-initdb.d/db-init.sh' + - './environments/qiita-db-init.sh:/docker-entrypoint-initdb.d/qiita-db-init.sh' - 'postgres-data:/var/lib/postgresql/data' + ports: + - "6543:5432" - keycloak: - image: quay.io/keycloak/keycloak:24.0.2 - command: ['start'] + qiita: + image: qiita:latest + command: ['./start_qiita.sh'] #executes bash script inside the container + stdin_open: true + tty: true + network_mode: host ports: - - "8282:8282" # as the HAproxy of BCF if configured to forward requests here - restart: unless-stopped + - "21174:21174" #wihtout nginx + restart: no depends_on: - - keycloak-db + - qiita-db env_file: - - './environments/keycloak.env' + - './environments/qiita.env' environment: - - KEYCLOAK_ADMIN=admin - - KC_DB=postgres - - KC_DB_URL_HOST=keycloak-db - - KC_DB_URL_PORT=5432 - - KC_DB_URL_DATABASE=keycloak - - KC_DB_USERNAME=keycloak - - KC_DB_SCHEMA=public - - KC_HTTP_HOST=0.0.0.0 - - KC_HTTP_ENABLED=false - - KC_HTTP_PORT=8282 - - KC_PROXY=edge - - KC_PROXY_HEADERS=forwarded - - KC_PROXY_ADDRESS_FORWARDING=true - - KC_HOSTNAME_URL=https://keycloak.jlab.bio - - KC_HOSTNAME_ADMIN_URL=https://keycloak.jlab.bio - - KC_LOG_LEVEL=WARN - #- KC_HOSTNAME_DEBUG=true - #- JAVA_OPTS_APPEND="-Djava.net.preferIPv4Stack=true" + - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt + - QIITA_CONFIG_FP=/qiita/qiita_core/support_files/config_test.cfg + volumes: postgres-data: - name: keycloak-postgres-data + name: qiita-postgres-data diff --git a/keycloak_compose.yaml b/keycloak_compose.yaml new file mode 100644 index 0000000..e581619 --- /dev/null +++ b/keycloak_compose.yaml @@ -0,0 +1,52 @@ +version: '3' + +services: + keycloak-db: + image: postgres:15 + container_name: keycloak-db + hostname: keycloak-db + restart: unless-stopped + env_file: + - ./environments/db.env + environment: + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + - KEYCLOAK_DB_NAME=keycloak + - KEYCLOAK_DB_USER=keycloak + volumes: + - './environments/db-init.sh:/docker-entrypoint-initdb.d/db-init.sh' + - 'postgres-data:/var/lib/postgresql/data' + + keycloak: + image: quay.io/keycloak/keycloak:24.0.2 + command: ['start'] + ports: + - "8282:8282" # as the HAproxy of BCF if configured to forward requests here + restart: unless-stopped + depends_on: + - keycloak-db + env_file: + - './environments/keycloak.env' + environment: + - KEYCLOAK_ADMIN=admin + - KC_DB=postgres + - KC_DB_URL_HOST=keycloak-db + - KC_DB_URL_PORT=5432 + - KC_DB_URL_DATABASE=keycloak + - KC_DB_USERNAME=keycloak + - KC_DB_SCHEMA=public + - KC_HTTP_HOST=0.0.0.0 + - KC_HTTP_ENABLED=false + - KC_HTTP_PORT=8282 + - KC_PROXY=edge + - KC_PROXY_HEADERS=forwarded + - KC_PROXY_ADDRESS_FORWARDING=true + - KC_HOSTNAME_URL=https://keycloak.jlab.bio + - KC_HOSTNAME_ADMIN_URL=https://keycloak.jlab.bio + - KC_LOG_LEVEL=WARN + #- KC_HOSTNAME_DEBUG=true + #- JAVA_OPTS_APPEND="-Djava.net.preferIPv4Stack=true" + +volumes: + postgres-data: + name: keycloak-postgres-data From f64b72b169278de291451d583c65e8bfeac7e7bd Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 16 May 2024 14:31:34 +0200 Subject: [PATCH 006/287] Add README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..efe00ff --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +**IMPORTANT: Have docker installed!** + +### Hopefully "foolproof" instructions: +1. Clone repository +2. Move into Image Folder `cd Images/qiita` +3. Build docker image `docker build . -f qiita/Dockerfile -t qiita` +4. Move to folder containing compose file `cd ../..` +5. Run docker compose `docker compose up` +6. To stop: Run `docker compose down` + - Use `docker compose down --volumes`if you wish to remove the database volume as well. \ No newline at end of file From d713ad2525db5c33b245f778791210c15582bcf9 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 23 May 2024 16:55:52 +0200 Subject: [PATCH 007/287] Add Keycloak to compose file --- compose.yaml | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/compose.yaml b/compose.yaml index 4baea57..fde9fb0 100644 --- a/compose.yaml +++ b/compose.yaml @@ -16,7 +16,7 @@ services: - './environments/qiita-db-init.sh:/docker-entrypoint-initdb.d/qiita-db-init.sh' - 'postgres-data:/var/lib/postgresql/data' ports: - - "6543:5432" + - "5432:5432" qiita: image: qiita:latest @@ -35,7 +35,42 @@ services: - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt - QIITA_CONFIG_FP=/qiita/qiita_core/support_files/config_test.cfg + keycloak_web: #from https://stackoverflow.com/questions/78071458/keycloak-docker-compose + image: quay.io/keycloak/keycloak:24.0.2 + container_name: keycloak_web + environment: + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://keycloakdb:5432/keycloak + KC_DB_USERNAME: keycloak + KC_DB_PASSWORD: password + + KC_HOSTNAME: localhost + KC_HOSTNAME_PORT: 8080 + KC_HOSTNAME_STRICT: false + KC_HOSTNAME_STRICT_HTTPS: false + + KC_LOG_LEVEL: info + KC_METRICS_ENABLED: true + KC_HEALTH_ENABLED: true + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + command: start-dev + depends_on: + - keycloakdb + ports: + - 8080:8080 + + keycloakdb: + image: postgres:15 + volumes: + - keycloak-postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_DB: keycloak + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: password volumes: postgres-data: name: qiita-postgres-data + keycloak-postgres-data: + name: keycloak-postgres-data \ No newline at end of file From 6bae7103a50cbb825fdc668ea58b49ee82bed176 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Fri, 24 May 2024 13:12:16 +0200 Subject: [PATCH 008/287] Now able to use local keycloak instance with Qiita via Docker --- Images/qiita/Dockerfile | 11 +- Images/qiita/config_qiita_oidc.cfg | 257 +++++++++++++++++++++++++++++ Images/qiita/start_qiita.sh | 2 + README.md | 18 +- 4 files changed, 282 insertions(+), 6 deletions(-) create mode 100644 Images/qiita/config_qiita_oidc.cfg diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 6ad1f9e..53ddd38 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -34,8 +34,8 @@ RUN pip install \ coverage #Clone the Qiita Repo -RUN git clone -b master https://github.com/qiita-spots/qiita.git - +#RUN git clone -b master https://github.com/qiita-spots/qiita.git +RUN git clone -b auth_oidc https://github.com/jlab/qiita.git #We need to install necessary dependencies #as well as some extra dependencies for psycopg2 to work @@ -53,8 +53,11 @@ RUN pip install "Jinja2<3.1" #Configuring the Qiita Config to run inside the container -RUN sed -i 's/BASE_URL = https:\/\/localhost:8383/BASE_URL = https:\/\/localhost:21174\//' qiita/qiita_core/support_files/config_test.cfg -RUN sed -i 's/\/home\/runner\/work\/qiita\/qiita\//\/qiita\//' qiita/qiita_core/support_files/config_test.cfg +#RUN sed -i 's/BASE_URL = https:\/\/localhost:8383/BASE_URL = https:\/\/localhost:21174\//' qiita/qiita_core/support_files/config_test.cfg +#RUN sed -i 's/\/home\/runner\/work\/qiita\/qiita\//\/qiita\//' qiita/qiita_core/support_files/config_test.cfg + +COPY config_qiita_oidc.cfg . +RUN chmod 777 config_qiita_oidc.cfg #Copy Bash Script to run Qiita to the container COPY start_qiita.sh . diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg new file mode 100644 index 0000000..c4e42ce --- /dev/null +++ b/Images/qiita/config_qiita_oidc.cfg @@ -0,0 +1,257 @@ +# WARNING!!!! DO NOT MODIFY THIS FILE +# IF YOU NEED TO PROVIDE YOUR OWN CONFIGURATION, COPY THIS FILE TO A NEW +# LOCATION AND EDIT THE COPY + +# ----------------------------------------------------------------------------- +# Copyright (c) 2014--, The Qiita Development Team. +# +# Distributed under the terms of the BSD 3-clause License. +# +# The full license is in the file LICENSE, distributed with this software. +# ----------------------------------------------------------------------------- + +# ------------------------------ Main settings -------------------------------- +[main] +# Change to FALSE in a production system +TEST_ENVIRONMENT = TRUE + +# Absolute path to the directory where log files are saved. If not given, no +# log file will be created +LOG_DIR = + +# Whether studies require admin approval to be made available +REQUIRE_APPROVAL = True + +# Base URL: DO NOT ADD TRAILING SLASH +BASE_URL = https://localhost:21174 + +# Download path files +UPLOAD_DATA_DIR = /qiita/qiita_db/support_files/test_data/uploads/ + +# Working directory path +WORKING_DIR = /qiita/qiita_db/support_files/test_data/working_dir/ + +# Maximum upload size (in Gb) +MAX_UPLOAD_SIZE = 100 + +# Path to the base directory where the data files are going to be stored +BASE_DATA_DIR = /qiita/qiita_db/support_files/test_data/ + +# Valid upload extension, comma separated. Empty for no uploads +VALID_UPLOAD_EXTENSION = fastq,fastq.gz,txt,tsv,sff,fna,qual + +# The script used to start the qiita environment, if any +# used to spawn private CLI to a cluster +QIITA_ENV = source activate qiita + +# Script used for launching private Qiita tasks +PRIVATE_LAUNCHER = qiita-private-launcher + +# Script used for launching plugins +PLUGIN_LAUNCHER = qiita-plugin-launcher + +# Plugins configuration directory +PLUGIN_DIR = + +# Webserver certificate file paths +CERTIFICATE_FILE = +KEY_FILE = + +# The value used to secure cookies used for user sessions. A suitable value can +# be generated with: +# +# python -c "from base64 import b64encode;\ +# from uuid import uuid4;\ +# print b64encode(uuid4().bytes + uuid4().bytes)" +COOKIE_SECRET = SECRET + +# The value used to secure JWTs for delegated permission artifact download. +JWT_SECRET = SUPER_SECRET + +# Address a user should write to when asking for help +HELP_EMAIL = foo@bar.com + +# The email address, Qiita sends internal notifications to a sys admin +SYSADMIN_EMAIL = jeff@bar.com + +# ----------------------------- SMTP settings ----------------------------- +[smtp] +# The hostname to connect to +# Google: smtp.google.com +HOST = localhost + +# The port to connect to the database +# Google: 587 +PORT = 25 + +# SSL needed (True or False) +# Google: True +SSL = False + +# The user name to connect with +USER = + +# The user password to connect with +PASSWORD = + +# The email to have messages sent from +EMAIL = example@domain.com + +# ----------------------------- Redis settings -------------------------------- +[redis] +HOST = localhost +PORT = 7777 +PASSWORD = +# The redis database you will use, redis has a max of 16. +# Qiita should have its own database +DB = 13 + +# ----------------------------- Postgres settings ----------------------------- +[postgres] +# The user name to connect to the database +USER = postgres + +# The administrator user, which can be used to create/drop environments +ADMIN_USER = postgres + +# The database to connect to +DATABASE = qiita_test + +# The host where the database lives on +HOST = localhost + +# The port to connect to the database +PORT = 5432 + +# The password to use to connect to the database +PASSWORD = postgres + +# The postgres password for the admin_user +ADMIN_PASSWORD = postgres + +# ----------------------------- Job Scheduler Settings ----------------------------- +[job_scheduler] +# The email address of the submitter of jobs +JOB_SCHEDULER_JOB_OWNER = user@somewhere.org + +# The number of seconds to wait between successive calls +JOB_SCHEDULER__POLLING_VALUE = 15 + +# Hard upper-limit on concurrently running validator jobs +JOB_SCHEDULER_PROCESSING_QUEUE_COUNT = 2 + +# ----------------------------- EBI settings ----------------------------- +[ebi] +# The user to use when submitting to EBI +EBI_SEQ_XFER_USER = Webin-41528 + +# Password for the above user +EBI_SEQ_XFER_PASS = + +# URL of EBI's FASP site +EBI_SEQ_XFER_URL = webin.ebi.ac.uk + +# URL of EBI's HTTPS dropbox +# live submission URL +#EBI_DROPBOX_URL = https://www.ebi.ac.uk/ena/submit/drop-box/submit/ +# testing URL +EBI_DROPBOX_URL = https://www-test.ebi.ac.uk/ena/submit/drop-box/submit/ + +# The name of the sequencing center to use when doing EBI submissions +EBI_CENTER_NAME = qiita-test + +# This string (with an underscore) will be prefixed to your EBI submission and +# study aliases +EBI_ORGANIZATION_PREFIX = example_organization + +# ----------------------------- VAMPS settings ----------------------------- +[vamps] +# general info to submit to vamps +USER = user +PASSWORD = password +URL = https://vamps.mbl.edu/mobe_workshop/getfile.php + +# ----------------------------- Portal settings ----------------------------- +[portal] + +# Portal the site is working under +PORTAL = QIITA + +# Portal subdirectory +PORTAL_DIR = + +# Full path to portal styling config file +PORTAL_FP = + +# The center latitude of the world map, shown on the Stats map. +# Defaults to 40.01027 (Boulder, CO, USA) +STATS_MAP_CENTER_LATITUDE = + +# The center longitude of the world map, shown on the Stats map. +# Defaults to -105.24827 (Boulder, CO, USA) +STATS_MAP_CENTER_LONGITUDE = + +# ----------------------------- iframes settings --------------------------- +[iframe] +# The real world QIIMP will always need to be accessed with https because Qiita +# runs on https too +QIIMP = https://localhost:8898/ + + +# --------------------- External Identity Provider settings -------------------- +# user authentication happens per default within Qiita, i.e. when a user logs in, +# the stored password hash and email address is compared against what a user +# just provided. You might however, use an external identity provider (IdP) to +# authenticate the user like +# google: https://developers.google.com/identity/protocols/oauth2 or +# github: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps or +# self hosted keycloak: https://www.keycloak.org/ +# Thus, you don't have to deal with user verification, reset passwords, ... +# Authorization (i.e. if the authorized user is allowed to use Qiita or which +# user level he/she gets assigned is an independent process. You can even use +# multiple independent external identity providers! +# Qiita currently only support the "open ID connect" protocol with the implicit flow. +# Each identity provider comes as its own config section [oidc_foo] and needs +# to specify the following five fields: +# +# Typical identity provider manage multiple "realms" and specific "clients" per realm +# You need to contact your IdP and register Qiita as a new "client". The IdP will +# provide you with the correct values. +# +# The authorization protocol requires three steps to obtain user information: +# 1) you identify as the correct client and ask the IdP for a request code +# You have to forward the user to the login page of your IdP. To let the IdP +# know how to come back to Qiita, you need to provide a redirect URL +# 2) you exchange the code for a user token +# 3) you obtain information about the user for the obtaines user token +# Typically, each step is implemented as a separate URL endpoint +# +# To activate IdP: comment out the following config section + +[oidc_localkeycloak] + +# client ID for Qiita as registered at your Identity Provider of choice +CLIENT_ID = qiita + +# client secret to verify Qiita as the correct client. Not all IdPs require +# a client secret! +CLIENT_SECRET = VrZOw326Pej0mFtlHi3fFu6plQeRs1CB + +# redirect URL (end point in your Qiita instance), to which the IdP redirects +# after user types in his/her credentials. If you don't want to change code in +# qiita_pet/webserver.py the URL must follow the pattern: +# base_URL/auth/login_OIDC/foo where foo is the name of this config section +# without the oidc_ prefix! +REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak + +# URL for step 1: obtain code +AUTHORIZE_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/auth + +# URL for step 2: obtain user token +ACCESS_TOKEN_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/token + +# URL for step 3: obtain user infos +USERINFO_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/userinfo + +# a speaking label for the Identity Provider. Section name is used if empty. +LABEL = localhost diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index bad4c42..13c0551 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -4,6 +4,8 @@ redis-server --daemonize yes --port 7777 redis-server --daemonize yes --port 6379 +export QIITA_CONFIG_FP="./config_qiita_oidc.cfg" + #building the database without ontologies qiita-env make --no-load-ontologies diff --git a/README.md b/README.md index efe00ff..fb3419c 100644 --- a/README.md +++ b/README.md @@ -6,5 +6,19 @@ 3. Build docker image `docker build . -f qiita/Dockerfile -t qiita` 4. Move to folder containing compose file `cd ../..` 5. Run docker compose `docker compose up` -6. To stop: Run `docker compose down` - - Use `docker compose down --volumes`if you wish to remove the database volume as well. \ No newline at end of file +6. Open `http://localhost:21174` +7. To stop: Run `docker compose down qiita qiita-db` + - Use `docker compose down --volumes`if you wish to remove the database volume as well. + +### IF YOU WANT TO USE LOCAL KEYCLOAK: + +1. Clone repository +2. Run `docker compose up keycloak_web keycloakdb` +3. Open `http://localhost:8080`, login admin pw admin +4. Configure Qiita as a service, create a user +5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration. +6. Open a new terminal, move into Image Folder `cd Images/qiita` +7. Build docker image `docker build . -f qiita/Dockerfile -t qiita` +8. Move to folder containing compose file `cd ../..` +9. Run docker compose `docker compose up qiita qiita-db` +10. Open `http://localhost:21174` \ No newline at end of file From 8c0fb5764a8b524917bb23d30d188a30c2959665 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Fri, 24 May 2024 13:17:43 +0200 Subject: [PATCH 009/287] Small changes, adding comments --- Images/qiita/Dockerfile | 5 +---- compose.yaml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 53ddd38..819aa39 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -52,10 +52,7 @@ RUN pip install -e qiita/. --no-binary redbiom RUN pip install "Jinja2<3.1" -#Configuring the Qiita Config to run inside the container -#RUN sed -i 's/BASE_URL = https:\/\/localhost:8383/BASE_URL = https:\/\/localhost:21174\//' qiita/qiita_core/support_files/config_test.cfg -#RUN sed -i 's/\/home\/runner\/work\/qiita\/qiita\//\/qiita\//' qiita/qiita_core/support_files/config_test.cfg - +#Copy modified config file to the container COPY config_qiita_oidc.cfg . RUN chmod 777 config_qiita_oidc.cfg diff --git a/compose.yaml b/compose.yaml index fde9fb0..4a6fc1b 100644 --- a/compose.yaml +++ b/compose.yaml @@ -33,7 +33,7 @@ services: - './environments/qiita.env' environment: - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt - - QIITA_CONFIG_FP=/qiita/qiita_core/support_files/config_test.cfg + - QIITA_CONFIG_FP=./config_qiita_oidc.cfg keycloak_web: #from https://stackoverflow.com/questions/78071458/keycloak-docker-compose image: quay.io/keycloak/keycloak:24.0.2 From d52e130a050b044b9b1b4c83d259a80ecae38428 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Fri, 24 May 2024 13:29:40 +0200 Subject: [PATCH 010/287] Comment out oidc from config file --- Images/qiita/config_qiita_oidc.cfg | 43 +++++++++++++++--------------- README.md | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index c4e42ce..08410ba 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -226,32 +226,33 @@ QIIMP = https://localhost:8898/ # 3) you obtain information about the user for the obtaines user token # Typically, each step is implemented as a separate URL endpoint # -# To activate IdP: comment out the following config section +# To activate IdP: remove comments from the following config section -[oidc_localkeycloak] +#[oidc_localkeycloak] -# client ID for Qiita as registered at your Identity Provider of choice -CLIENT_ID = qiita +## client ID for Qiita as registered at your Identity Provider of choice +#CLIENT_ID = qiita -# client secret to verify Qiita as the correct client. Not all IdPs require -# a client secret! -CLIENT_SECRET = VrZOw326Pej0mFtlHi3fFu6plQeRs1CB +## client secret to verify Qiita as the correct client. Not all IdPs require +## a client secret! +## ADD CLIENT SECRET FROM YOUR LOCAL KEYCLOAK +#CLIENT_SECRET = -# redirect URL (end point in your Qiita instance), to which the IdP redirects -# after user types in his/her credentials. If you don't want to change code in -# qiita_pet/webserver.py the URL must follow the pattern: -# base_URL/auth/login_OIDC/foo where foo is the name of this config section -# without the oidc_ prefix! -REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak +## redirect URL (end point in your Qiita instance), to which the IdP redirects +## after user types in his/her credentials. If you don't want to change code in +## qiita_pet/webserver.py the URL must follow the pattern: +## base_URL/auth/login_OIDC/foo where foo is the name of this config section +## without the oidc_ prefix! +#REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak -# URL for step 1: obtain code -AUTHORIZE_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/auth +## URL for step 1: obtain code +#AUTHORIZE_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/auth -# URL for step 2: obtain user token -ACCESS_TOKEN_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/token +## URL for step 2: obtain user token +#ACCESS_TOKEN_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/token -# URL for step 3: obtain user infos -USERINFO_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/userinfo +## URL for step 3: obtain user infos +#USERINFO_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/userinfo -# a speaking label for the Identity Provider. Section name is used if empty. -LABEL = localhost +## a speaking label for the Identity Provider. Section name is used if empty. +#LABEL = localhost diff --git a/README.md b/README.md index fb3419c..a9e364c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ 2. Run `docker compose up keycloak_web keycloakdb` 3. Open `http://localhost:8080`, login admin pw admin 4. Configure Qiita as a service, create a user -5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration. +5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, comment out necessary oidc configuration part. 6. Open a new terminal, move into Image Folder `cd Images/qiita` 7. Build docker image `docker build . -f qiita/Dockerfile -t qiita` 8. Move to folder containing compose file `cd ../..` From 423e89545b88ee7ca949c3838adeb12e16c8eb78 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Fri, 7 Jun 2024 07:32:34 +0200 Subject: [PATCH 011/287] Change structure of config to adhere to latest implemented version of the config_manager --- Images/qiita/config_qiita_oidc.cfg | 57 +++++++++++++++++------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index 08410ba..8e44531 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -17,7 +17,7 @@ TEST_ENVIRONMENT = TRUE # Absolute path to the directory where log files are saved. If not given, no # log file will be created -LOG_DIR = +LOG_DIR = /qiita/ # Whether studies require admin approval to be made available REQUIRE_APPROVAL = True @@ -201,8 +201,8 @@ QIIMP = https://localhost:8898/ # --------------------- External Identity Provider settings -------------------- # user authentication happens per default within Qiita, i.e. when a user logs in, # the stored password hash and email address is compared against what a user -# just provided. You might however, use an external identity provider (IdP) to -# authenticate the user like +# just provided. You might however, use an external identity provider (IdP) to +# authenticate the user like # google: https://developers.google.com/identity/protocols/oauth2 or # github: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps or # self hosted keycloak: https://www.keycloak.org/ @@ -226,33 +226,40 @@ QIIMP = https://localhost:8898/ # 3) you obtain information about the user for the obtaines user token # Typically, each step is implemented as a separate URL endpoint # -# To activate IdP: remove comments from the following config section - -#[oidc_localkeycloak] +# To activate IdP: comment out the following config section +# [oidc_localkeycloak] +# ## client ID for Qiita as registered at your Identity Provider of choice -#CLIENT_ID = qiita - +# CLIENT_ID = qiita +# ## client secret to verify Qiita as the correct client. Not all IdPs require ## a client secret! -## ADD CLIENT SECRET FROM YOUR LOCAL KEYCLOAK -#CLIENT_SECRET = +# CLIENT_SECRET = supersecretString -## redirect URL (end point in your Qiita instance), to which the IdP redirects -## after user types in his/her credentials. If you don't want to change code in +# +## redirect URL (end point in your Qiita instance), to which the IdP redirects +## after user types in his/her credentials. If you don't want to change code in ## qiita_pet/webserver.py the URL must follow the pattern: -## base_URL/auth/login_OIDC/foo where foo is the name of this config section +## base_URL/auth/login_OIDC/foo where foo is the name of this config section ## without the oidc_ prefix! -#REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak - -## URL for step 1: obtain code -#AUTHORIZE_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/auth - -## URL for step 2: obtain user token -#ACCESS_TOKEN_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/token - -## URL for step 3: obtain user infos -#USERINFO_URL = http://localhost:8080/realms/qiita_realm/protocol/openid-connect/userinfo - +# REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak +# +## The URL of the well-known json document, specifying how API end points +## like 'authorize', 'token' or 'userinfo' are defined. See e.g. +## https://swagger.io/docs/specification/authentication/ +## openid-connect-discovery/ +# WELLKNOWN_URI = http://localhost:9999/realms/qiita_realm/.well-known/openid-configuration +# ## a speaking label for the Identity Provider. Section name is used if empty. -#LABEL = localhost +# LABEL = localkeycloak +# +## The scope, i.e. fields about a user, which Qiita requests from the +## Identity Provider, e.g. "profile email eduperson_orcid". +## Will be automatically extended by the scope "openid", to enable the +## "authorize_code" OIDC flow. +# SCOPE = openid +# +##Optional. Name of a file in qiita_pet/static/img that shall be +##displayed for login through Service Provider, instead of a plain button +# LOGO = From 1ff79f5cbfe71f2eddc4d550b6b92f6a24d6493a Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Fri, 7 Jun 2024 07:43:11 +0200 Subject: [PATCH 012/287] Upadte gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d967199..eb83339 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -environments/db.env -environments/keycloak.env +environments/*.env From d45b5d8fc8caaf612cf30f11b2c4d2182ecc95de Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Fri, 7 Jun 2024 07:59:47 +0200 Subject: [PATCH 013/287] Address Stefans changes --- Images/qiita/Dockerfile | 43 +++++++++++++++++------------------ Images/qiita/start_qiita.sh | 16 ++++++++----- README.md | 4 +++- compose.yaml | 35 ++++++++++++++++++++-------- environments/qiita-db-init.sh | 2 +- 5 files changed, 61 insertions(+), 39 deletions(-) diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 819aa39..25ce2a9 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG MINIFORGE_VERSION=24.1.2-0 @@ -6,9 +6,12 @@ ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} RUN apt-get -y update -RUN apt-get -y install \ +RUN apt-get -y --fix-missing install \ git \ - wget + wget \ + libpq-dev \ + python3-dev \ + gcc RUN apt-get -y install build-essential # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile @@ -31,36 +34,32 @@ RUN pip install \ sphinx-bootstrap-theme \ nose-timer \ Click \ - coverage + coverage \ + psycopg2-binary -#Clone the Qiita Repo -#RUN git clone -b master https://github.com/qiita-spots/qiita.git +#cClone the Qiita Repo +# RUN git clone -b master https://github.com/qiita-spots/qiita.git RUN git clone -b auth_oidc https://github.com/jlab/qiita.git -#We need to install necessary dependencies -#as well as some extra dependencies for psycopg2 to work +# We need to install necessary dependencies +# as well as some extra dependencies for psycopg2 to work RUN git clone https://github.com/psycopg/psycopg2.git -RUN apt-get -y update -RUN apt-get -y install libpq-dev python3-dev gcc -RUN pg_config --version RUN export PATH=/usr/lib/postgresql/14.11/bin/:$PATH -RUN pip install psycopg2-binary RUN pip install -e psycopg2/. -#Install pip packaages for Qiita -RUN pip install -e qiita/. --no-binary redbiom -RUN pip install "Jinja2<3.1" +# Install pip packaages for Qiita +RUN pip install -e qiita --no-binary redbiom -#Copy modified config file to the container +# Copy modified config file to the container COPY config_qiita_oidc.cfg . -RUN chmod 777 config_qiita_oidc.cfg +RUN chmod 755 config_qiita_oidc.cfg -#Copy Bash Script to run Qiita to the container +# Copy Bash Script to run Qiita to the container COPY start_qiita.sh . -RUN chmod 777 start_qiita.sh +RUN chmod 755 start_qiita.sh -#I will leave this ENTRYPOINT here as a comment in case debugging -#is necessary -#ENTRYPOINT ["/bin/bash"] +# I will leave this ENTRYPOINT here as a comment in case debugging +# is necessary +# SHELL ["/bin/bash"] ENTRYPOINT ["conda", "run", "-n", "qiita", "./start_qiita.sh"] \ No newline at end of file diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 13c0551..604cc06 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -1,13 +1,17 @@ #!/bin/bash -#first we start the redis server +# first we start the redis server redis-server --daemonize yes --port 7777 redis-server --daemonize yes --port 6379 -export QIITA_CONFIG_FP="./config_qiita_oidc.cfg" +export QIITA_CONFIG_FP="/config_qiita_oidc.cfg" -#building the database without ontologies -qiita-env make --no-load-ontologies +conda list -#starting the webserver without building the docs -qiita pet webserver --no-build-docs start \ No newline at end of file +# building the database without ontologies +qiita-env make --no-load-ontologies #|| true + +# starting the webserver without building the docs +qiita pet webserver --no-build-docs start + +# supervisord -c ./qiita/qiita_pet/supervisor_example.conf \ No newline at end of file diff --git a/README.md b/README.md index a9e364c..9070e3f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ **IMPORTANT: Have docker installed!** +**THIS VERSION CURRENTLY ONLY WORKS WITH DOCKER, NOT WITH PODMAN** +**FOR TESTING ON LOCAL MACHINES** ### Hopefully "foolproof" instructions: 1. Clone repository @@ -16,7 +18,7 @@ 2. Run `docker compose up keycloak_web keycloakdb` 3. Open `http://localhost:8080`, login admin pw admin 4. Configure Qiita as a service, create a user -5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, comment out necessary oidc configuration part. +5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, remove # from necessary oidc block. 6. Open a new terminal, move into Image Folder `cd Images/qiita` 7. Build docker image `docker build . -f qiita/Dockerfile -t qiita` 8. Move to folder containing compose file `cd ../..` diff --git a/compose.yaml b/compose.yaml index 4a6fc1b..e5669a5 100644 --- a/compose.yaml +++ b/compose.yaml @@ -10,8 +10,6 @@ services: environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - - POSTGRES_DB_NAME=postgres - - POSTGRES_DB_USER=postgres volumes: - './environments/qiita-db-init.sh:/docker-entrypoint-initdb.d/qiita-db-init.sh' - 'postgres-data:/var/lib/postgresql/data' @@ -20,12 +18,13 @@ services: qiita: image: qiita:latest - command: ['./start_qiita.sh'] #executes bash script inside the container + command: ['./start_qiita.sh'] # executes bash script inside the container + # entrypoint: /bin/bash stdin_open: true tty: true network_mode: host ports: - - "21174:21174" #wihtout nginx + - "21174:21174" # wihtout nginx restart: no depends_on: - qiita-db @@ -33,9 +32,12 @@ services: - './environments/qiita.env' environment: - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt - - QIITA_CONFIG_FP=./config_qiita_oidc.cfg + - QIITA_CONFIG_FP=/config_qiita_oidc.cfg + volumes: + - qiita-data:/qiita - keycloak_web: #from https://stackoverflow.com/questions/78071458/keycloak-docker-compose + + keycloak_web: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose image: quay.io/keycloak/keycloak:24.0.2 container_name: keycloak_web environment: @@ -45,7 +47,7 @@ services: KC_DB_PASSWORD: password KC_HOSTNAME: localhost - KC_HOSTNAME_PORT: 8080 + KC_HOSTNAME_PORT: 9999 KC_HOSTNAME_STRICT: false KC_HOSTNAME_STRICT_HTTPS: false @@ -58,7 +60,7 @@ services: depends_on: - keycloakdb ports: - - 8080:8080 + - 9999:8080 keycloakdb: image: postgres:15 @@ -68,9 +70,24 @@ services: POSTGRES_DB: keycloak POSTGRES_USER: keycloak POSTGRES_PASSWORD: password + + # nginx: + # image: nginx_qiita:latest + # ports: + # - "8080:8080" + # command: ['./start_nginx.sh'] + # command: /bin/bash + # entrypoint: /bin/bash + # stdin_open: true + # tty: true + # restart: no + # volumes: + # - qiita:/qiita/ volumes: postgres-data: name: qiita-postgres-data keycloak-postgres-data: - name: keycloak-postgres-data \ No newline at end of file + name: keycloak-postgres-data + qiita-data: + name: qiita-data diff --git a/environments/qiita-db-init.sh b/environments/qiita-db-init.sh index 97729bf..3534aa4 100644 --- a/environments/qiita-db-init.sh +++ b/environments/qiita-db-init.sh @@ -4,5 +4,5 @@ set -e set -u psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" "$POSTGRES_DB" <<-EOSQL - ALTER DATABASE "$POSTGRES_DB_NAME" OWNER TO "$POSTGRES_USER" + ALTER DATABASE "$POSTGRES_DB" OWNER TO "$POSTGRES_USER" EOSQL From 54847f8c4fcbb0008e114ac7be155e1c3d3a4d22 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Fri, 7 Jun 2024 08:07:01 +0200 Subject: [PATCH 014/287] .gitignore should untrack env files now --- environments/qiita.env | 3 --- environments/qiita_db.env | 1 - 2 files changed, 4 deletions(-) delete mode 100644 environments/qiita.env delete mode 100644 environments/qiita_db.env diff --git a/environments/qiita.env b/environments/qiita.env deleted file mode 100644 index ddadb4e..0000000 --- a/environments/qiita.env +++ /dev/null @@ -1,3 +0,0 @@ -QIITA_ROOTCA_CERT=`pwd`/qiita_core/support_files/ci_rootca.crt -QIITA_CONFIG_FP=`pwd`/qiita_core/support_files/config_test.cfg - diff --git a/environments/qiita_db.env b/environments/qiita_db.env deleted file mode 100644 index af9fa55..0000000 --- a/environments/qiita_db.env +++ /dev/null @@ -1 +0,0 @@ -POSTGRES_PASSWORD=postgres From e15d41a2da280f717885d00cf3036b104f5ccce5 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Tue, 11 Jun 2024 11:35:52 +0200 Subject: [PATCH 015/287] Add example files for qiita env files --- environments/qiita.env.example | 2 ++ environments/qiita_db.env.example | 1 + 2 files changed, 3 insertions(+) create mode 100644 environments/qiita.env.example create mode 100644 environments/qiita_db.env.example diff --git a/environments/qiita.env.example b/environments/qiita.env.example new file mode 100644 index 0000000..74ee17a --- /dev/null +++ b/environments/qiita.env.example @@ -0,0 +1,2 @@ +# This is a place for additional configurations to your Qiita installation +# which are not addressed in the Qiita image itself \ No newline at end of file diff --git a/environments/qiita_db.env.example b/environments/qiita_db.env.example new file mode 100644 index 0000000..f8ac7cf --- /dev/null +++ b/environments/qiita_db.env.example @@ -0,0 +1 @@ +POSTGRES_PASSWORD=supersecretpassword \ No newline at end of file From 8b7039996fabb5a7d4ccf0e894411375c00b8c52 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Tue, 11 Jun 2024 11:40:03 +0200 Subject: [PATCH 016/287] Adjust README --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9070e3f..953f6ec 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,10 @@ 2. Move into Image Folder `cd Images/qiita` 3. Build docker image `docker build . -f qiita/Dockerfile -t qiita` 4. Move to folder containing compose file `cd ../..` -5. Run docker compose `docker compose up` -6. Open `http://localhost:21174` -7. To stop: Run `docker compose down qiita qiita-db` +5. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. +6. Run docker compose `docker compose up` +7. Open `http://localhost:21174` +8. To stop: Run `docker compose down qiita qiita-db` - Use `docker compose down --volumes`if you wish to remove the database volume as well. ### IF YOU WANT TO USE LOCAL KEYCLOAK: @@ -22,5 +23,6 @@ 6. Open a new terminal, move into Image Folder `cd Images/qiita` 7. Build docker image `docker build . -f qiita/Dockerfile -t qiita` 8. Move to folder containing compose file `cd ../..` -9. Run docker compose `docker compose up qiita qiita-db` -10. Open `http://localhost:21174` \ No newline at end of file +9. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. +10. Run docker compose `docker compose up qiita qiita-db` +11. Open `http://localhost:21174` \ No newline at end of file From dc6ff8dcf75373956a3a18413079156ded94e08a Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Tue, 11 Jun 2024 14:30:11 +0200 Subject: [PATCH 017/287] Start Qiita using supervisord (still without nginx) --- Images/qiita/Dockerfile | 3 +++ Images/qiita/start_qiita.sh | 6 ++--- Images/qiita/supervisor_foreground.conf | 34 +++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 Images/qiita/supervisor_foreground.conf diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 25ce2a9..2b84339 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -59,6 +59,9 @@ RUN chmod 755 config_qiita_oidc.cfg COPY start_qiita.sh . RUN chmod 755 start_qiita.sh +COPY supervisor_foreground.conf . +RUN chmod 755 supervisor_foreground.conf + # I will leave this ENTRYPOINT here as a comment in case debugging # is necessary # SHELL ["/bin/bash"] diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 604cc06..0df39f5 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -9,9 +9,9 @@ export QIITA_CONFIG_FP="/config_qiita_oidc.cfg" conda list # building the database without ontologies -qiita-env make --no-load-ontologies #|| true +qiita-env make --no-load-ontologies # || true # starting the webserver without building the docs -qiita pet webserver --no-build-docs start +# qiita pet webserver --no-build-docs start -# supervisord -c ./qiita/qiita_pet/supervisor_example.conf \ No newline at end of file +supervisord -c /supervisor_foreground.conf \ No newline at end of file diff --git a/Images/qiita/supervisor_foreground.conf b/Images/qiita/supervisor_foreground.conf new file mode 100644 index 0000000..42aea50 --- /dev/null +++ b/Images/qiita/supervisor_foreground.conf @@ -0,0 +1,34 @@ +[supervisorctl] +serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket + +[supervisord] +logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log +loglevel=debug ; log level; default info; others: debug,warn,trace +pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid +nodaemon=true + +[include] +files=/home/travis/miniconda3/envs/qiita/bin + +[group:qiita_all] +programs=qiita_workers_0,qiita_workers_1,qiita_workers_2,qiita_master ; each refers to 'x' in [program:x] definitions + +[program:qiita_master] +command=qiita pet webserver --no-build-docs start --port 21174 --master +process_name=%(program_name)s ; process_name expr (default %(program_name)s) +numprocs=1 ; number of processes copies to start (def 1) + +[program:qiita_workers_0] +command=qiita pet webserver --no-build-docs start --port 21175 +process_name=%(program_name)s ; process_name expr (default %(program_name)s) +numprocs=1 ; number of processes copies to start (def 1) + +[program:qiita_workers_1] +command=qiita pet webserver --no-build-docs start --port 21176 +process_name=%(program_name)s ; process_name expr (default %(program_name)s) +numprocs=1 ; number of processes copies to start (def 1) + +[program:qiita_workers_2] +command=qiita pet webserver --no-build-docs start --port 21177 +process_name=%(program_name)s ; process_name expr (default %(program_name)s) +numprocs=1 ; number of processes copies to start (def 1) From 2afb70b854a82b54e2a432981a088c9918fa98a8 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 12 Jun 2024 14:18:18 +0200 Subject: [PATCH 018/287] Change base URL for Qiita to nginx port --- Images/qiita/config_qiita_oidc.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index 8e44531..b9913b7 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -23,7 +23,7 @@ LOG_DIR = /qiita/ REQUIRE_APPROVAL = True # Base URL: DO NOT ADD TRAILING SLASH -BASE_URL = https://localhost:21174 +BASE_URL = https://localhost:8383 # Download path files UPLOAD_DATA_DIR = /qiita/qiita_db/support_files/test_data/uploads/ From c9235769bc56e518e8b45bff0aa171758a0e14d2 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 12 Jun 2024 14:18:33 +0200 Subject: [PATCH 019/287] Add nginx image --- Images/nginx/Dockerfile | 31 ++++++++++++ Images/nginx/nginx_qiita.conf | 92 +++++++++++++++++++++++++++++++++++ Images/nginx/start_nginx.sh | 4 ++ 3 files changed, 127 insertions(+) create mode 100644 Images/nginx/Dockerfile create mode 100644 Images/nginx/nginx_qiita.conf create mode 100644 Images/nginx/start_nginx.sh diff --git a/Images/nginx/Dockerfile b/Images/nginx/Dockerfile new file mode 100644 index 0000000..939debd --- /dev/null +++ b/Images/nginx/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:22.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y install \ + git \ + wget +RUN apt-get -y install build-essential +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ + conda init +RUN conda create --quiet --yes -n nginx nginx + +COPY nginx_qiita.conf . +COPY start_nginx.sh . + +RUN chmod 777 nginx_qiita.conf +RUN chmod 777 start_nginx.sh + +RUN mkdir /var/log/nginx + +#ENTRYPOINT ["/bin/bash", "-l", "-c" ] +ENTRYPOINT ["conda", "run", "-n", "nginx", "./start_nginx.sh"] \ No newline at end of file diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf new file mode 100644 index 0000000..fbca638 --- /dev/null +++ b/Images/nginx/nginx_qiita.conf @@ -0,0 +1,92 @@ +user nobody nogroup; +daemon off; +error_log /var/log/nginx/error_log warn; + +events { + worker_connections 1024; +} + +http { + client_max_body_size 7M; # increase maximum body size from default 1M to match https://github.com/qiita-spots/qiita/blob/ac62aba5333f537c32e213855edc39c273aa9871/qiita_pet/static/vendor/js/resumable-uploader.js#L51 (which is 3M). Note that resumable-uploader.js's last chunk can be max. twice as large as chunk size, see: https://github.com/23/resumable.js/issues/51 + + # ports to redirect for mainqiita + upstream mainqiita { + server localhost:21174; + server localhost:21175; + server localhost:21176; + server localhost:21177; + } + + # define variables for the actions that shall be taken for websocket handshake + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + # listening to 8080 and redirecting to https + #server { + # listen 8383; + # server_name localhost; + # return 301 https://$server_name$request_uri; + #} + + server { + listen 8383 ssl; + server_name _; + merge_slashes off; + + ssl_certificate /qiita/qiita_core/support_files/ci_server.crt; + ssl_certificate_key /qiita/qiita_core/support_files/ci_server.key; + + ssl_session_timeout 5m; + + # no catche + expires off; + + port_in_redirect off; + + # download configuration, based on: + # https://groups.google.com/forum/#!topic/python-tornado/sgadmx8Hd_s + + # protected location for working diretory + location /protected-working_dir/ { + internal; + + # CHANGE ME: This should match the WORKING_DIR in your qiita + # config. E.g., + alias /qiita/qiita_db/support_files/test_data/working_dir/; + } + + # protected location + location /protected/ { + internal; + + # CHANGE ME: This should match the BASE_DATA_DIR in your qiita + # config. E.g., + alias /qiita/qiita_db/support_files/test_data/; + } + + # enables communiction through websockets. + # Currently, only endpoints /consumer/, /analysis/selected/socket/, and /study/list/socket/ use websockets + # not needed for our local docker setup + # location ~ ^/(consumer|analysis/selected/socket|study/list/socket)/ { + # proxy_pass $scheme://mainqiita; + # proxy_set_header Host $http_host; + # proxy_redirect http:// https://; + # proxy_http_version 1.1; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header Upgrade $http_upgrade; + # proxy_set_header Connection $connection_upgrade; + # proxy_set_header X-Forwarded-Host $http_host; + # } + + location / { + proxy_pass $scheme://mainqiita; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Accept-Encoding identity; + } + } +} diff --git a/Images/nginx/start_nginx.sh b/Images/nginx/start_nginx.sh new file mode 100644 index 0000000..0296a80 --- /dev/null +++ b/Images/nginx/start_nginx.sh @@ -0,0 +1,4 @@ +#!/bin/bash +mkdir -p /opt/conda/envs/nginx/var/run/nginx/ + +nginx -c /nginx_qiita.conf \ No newline at end of file From ae6efe35fdbcef583e1c1c1b546b30e487b039a7 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 12 Jun 2024 14:19:47 +0200 Subject: [PATCH 020/287] Add nginx --- compose.yaml | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/compose.yaml b/compose.yaml index e5669a5..02a3696 100644 --- a/compose.yaml +++ b/compose.yaml @@ -24,10 +24,12 @@ services: tty: true network_mode: host ports: - - "21174:21174" # wihtout nginx + # - "21174:21174" # wihtout nginx + - 8383:8383 restart: no depends_on: - qiita-db + - nginx env_file: - './environments/qiita.env' environment: @@ -71,18 +73,17 @@ services: POSTGRES_USER: keycloak POSTGRES_PASSWORD: password - # nginx: - # image: nginx_qiita:latest - # ports: - # - "8080:8080" - # command: ['./start_nginx.sh'] - # command: /bin/bash - # entrypoint: /bin/bash - # stdin_open: true - # tty: true - # restart: no - # volumes: - # - qiita:/qiita/ + nginx: + image: nginx_qiita:latest + ports: + - "8383:8383" + command: ['./start_nginx.sh'] + network_mode: host + stdin_open: true + tty: true + restart: no + volumes: + - qiita-data:/qiita volumes: postgres-data: From 14cdc057a1d2e7c718ce2531ff44b6f41857af45 Mon Sep 17 00:00:00 2001 From: sjanssen2 Date: Thu, 13 Jun 2024 09:02:21 +0200 Subject: [PATCH 021/287] compile nginx with mod_zip instead of conda pre-compiled version --- Images/qiita/Dockerfile | 55 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 2b84339..3a345b4 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -1,17 +1,23 @@ FROM ubuntu:24.04 ARG MINIFORGE_VERSION=24.1.2-0 +ARG MODZIP_VERSION=1.3.0 +ARG NGINX_VERSION=1.26.0 ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} RUN apt-get -y update +# install following packages for nginx compilation: libpcre2-dev, libxslt-dev and libgd-dev RUN apt-get -y --fix-missing install \ git \ wget \ libpq-dev \ python3-dev \ - gcc + gcc \ + libpcre2-dev \ + libxslt-dev \ + libgd-dev RUN apt-get -y install build-essential # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile @@ -22,7 +28,7 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init # create conda env for qiita with all necessary dependencies (conda and pip) -RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy nginx cython anaconda::redis +RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy cython anaconda::redis # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 @@ -36,6 +42,51 @@ RUN pip install \ Click \ coverage \ psycopg2-binary + +# manually compile nginx to enable mod_zip +RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz +RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz +RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz +RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz +# fix include for the iconv header +RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c +# ensure runtime library paths are correct and openssl headers can be found at compile time +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ + --http-log-path=var/log/nginx/access.log \ + --error-log-path=var/log/nginx/error.log \ + --pid-path=var/run/nginx/nginx.pid \ + --lock-path=var/run/nginx/nginx.lock \ + --http-client-body-temp-path=var/tmp/nginx/client \ + --http-proxy-temp-path=var/tmp/nginx/proxy \ + --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ + --http-scgi-temp-path=var/tmp/nginx/scgi \ + --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ + --sbin-path=sbin/nginx \ + --conf-path=etc/nginx/nginx.conf \ + --modules-path=lib/nginx/modules \ + --with-threads \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_realip_module \ + --with-http_addition_module \ + --with-http_sub_module \ + --with-http_gunzip_module \ + --with-http_gzip_static_module \ + --with-http_auth_request_module \ + --with-http_secure_link_module \ + --with-http_stub_status_module \ + --with-http_xslt_module=dynamic \ + --with-stream=dynamic \ + --with-http_image_filter_module=dynamic \ + --with-pcre \ + --with-pcre-jit \ + --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ + --with-ld-opt="" \ + --prefix=/usr/local \ + --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ + --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install #cClone the Qiita Repo # RUN git clone -b master https://github.com/qiita-spots/qiita.git From fe8a83cc6a82b7a5b0f790c6d6e9284a21830133 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Tue, 18 Jun 2024 16:53:35 +0200 Subject: [PATCH 022/287] Enable Logging with mounted file on machine + update README with additional docker commands --- Images/nginx/nginx_qiita.conf | 3 ++- Images/qiita/Dockerfile | 13 +++++++++---- Images/qiita/config_qiita_oidc.cfg | 4 ++-- Images/qiita/start_qiita.sh | 2 +- Images/qiita/supervisor_foreground.conf | 4 ++-- README.md | 18 ++++++++++++------ compose.yaml | 11 +++++++++++ 7 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf index fbca638..ef5478e 100644 --- a/Images/nginx/nginx_qiita.conf +++ b/Images/nginx/nginx_qiita.conf @@ -1,6 +1,7 @@ user nobody nogroup; daemon off; -error_log /var/log/nginx/error_log warn; +# error_log /var/log/nginx/error_log warn; +error_log /qiita_logs/nginx_error_log warn; events { worker_connections 1024; diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 2b84339..519fb8e 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -1,6 +1,8 @@ FROM ubuntu:24.04 ARG MINIFORGE_VERSION=24.1.2-0 +ARG MODZIP_VERSION=1.3.0 +ARG NGINX_VERSION=1.26.0 ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} @@ -11,7 +13,10 @@ RUN apt-get -y --fix-missing install \ wget \ libpq-dev \ python3-dev \ - gcc + gcc \ + libpcre2-dev \ + libxslt-dev \ + libgd-dev RUN apt-get -y install build-essential # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile @@ -22,7 +27,7 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init # create conda env for qiita with all necessary dependencies (conda and pip) -RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy nginx cython anaconda::redis +RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy cython anaconda::redis # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 @@ -52,8 +57,8 @@ RUN pip install -e qiita --no-binary redbiom # Copy modified config file to the container -COPY config_qiita_oidc.cfg . -RUN chmod 755 config_qiita_oidc.cfg +COPY config_qiita_oidc.cfg /qiita/ +RUN chmod 755 /qiita/config_qiita_oidc.cfg # Copy Bash Script to run Qiita to the container COPY start_qiita.sh . diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index b9913b7..e812b1a 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -17,7 +17,7 @@ TEST_ENVIRONMENT = TRUE # Absolute path to the directory where log files are saved. If not given, no # log file will be created -LOG_DIR = /qiita/ +LOG_DIR = /qiita_logs/ # Whether studies require admin approval to be made available REQUIRE_APPROVAL = True @@ -51,7 +51,7 @@ PRIVATE_LAUNCHER = qiita-private-launcher PLUGIN_LAUNCHER = qiita-plugin-launcher # Plugins configuration directory -PLUGIN_DIR = +PLUGIN_DIR = /qiita/plugins/ # Webserver certificate file paths CERTIFICATE_FILE = diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 0df39f5..377db2d 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -4,7 +4,7 @@ redis-server --daemonize yes --port 7777 redis-server --daemonize yes --port 6379 -export QIITA_CONFIG_FP="/config_qiita_oidc.cfg" +export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" conda list diff --git a/Images/qiita/supervisor_foreground.conf b/Images/qiita/supervisor_foreground.conf index 42aea50..1016fe2 100644 --- a/Images/qiita/supervisor_foreground.conf +++ b/Images/qiita/supervisor_foreground.conf @@ -2,9 +2,9 @@ serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket [supervisord] -logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log +logfile=/qiita_logs/supervisord.log ; main log file; default $CWD/supervisord.log loglevel=debug ; log level; default info; others: debug,warn,trace -pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid +pidfile=/qiita_logs/supervisord.pid ; supervisord pidfile; default supervisord.pid nodaemon=true [include] diff --git a/README.md b/README.md index 953f6ec..1247153 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,21 @@ **FOR TESTING ON LOCAL MACHINES** ### Hopefully "foolproof" instructions: +0. Log files will be mounted at /tmp/qiita_logs on your local machine. Make sure the directory exists and is accessible for you. Otherwise, change the file path to your desired path in the compose file as well as in the qiita, nginx and supervisord conf. 1. Clone repository 2. Move into Image Folder `cd Images/qiita` 3. Build docker image `docker build . -f qiita/Dockerfile -t qiita` -4. Move to folder containing compose file `cd ../..` -5. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. -6. Run docker compose `docker compose up` -7. Open `http://localhost:21174` -8. To stop: Run `docker compose down qiita qiita-db` - - Use `docker compose down --volumes`if you wish to remove the database volume as well. +4. Build the nginx Image the same way as the qiita image, only in the nginx folder. +5. Move to folder containing compose file `cd ../..` +6. Copy the `qiita_db.env.example` and the `qiita.env.example` 7iles, configure them to your needs, and delete the `.example` from the file names. +7. Run docker compose `docker compose up qiita-db nginx qiita` +8. Open `http://localhost:21174` +9. To stop: Run `docker compose down qiita nginx qiita-db` + - Use `docker compose down qiita nginx qiita-db --volumes`if you wish to remove all associated volumes as well. + +Extras: +- If you want to remove a specific volume `docker volume rm ` +- If you want to access a container `docker ps`to fetch the ID and `docker exec -it bash` ### IF YOU WANT TO USE LOCAL KEYCLOAK: diff --git a/compose.yaml b/compose.yaml index 02a3696..b26d781 100644 --- a/compose.yaml +++ b/compose.yaml @@ -37,6 +37,7 @@ services: - QIITA_CONFIG_FP=/config_qiita_oidc.cfg volumes: - qiita-data:/qiita + - logs:/qiita_logs keycloak_web: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose @@ -84,6 +85,8 @@ services: restart: no volumes: - qiita-data:/qiita + - logs:/qiita_logs + volumes: postgres-data: @@ -92,3 +95,11 @@ volumes: name: keycloak-postgres-data qiita-data: name: qiita-data + logs: + name: logs + driver: local + driver_opts: + o: bind + type: none + device: /tmp/qiita_logs + From 078ec0283b11d98c39f9cfcbcbbe9fbf3d328329 Mon Sep 17 00:00:00 2001 From: sjanssen2 Date: Tue, 18 Jun 2024 17:08:41 +0200 Subject: [PATCH 023/287] use non-default port for postgress server for scenarios where the user already runs an existing postgress server outside of docker --- Images/qiita/config_qiita_oidc.cfg | 2 +- compose.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index b9913b7..6179f80 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -121,7 +121,7 @@ DATABASE = qiita_test HOST = localhost # The port to connect to the database -PORT = 5432 +PORT = 5433 # The password to use to connect to the database PASSWORD = postgres diff --git a/compose.yaml b/compose.yaml index 02a3696..e2bc089 100644 --- a/compose.yaml +++ b/compose.yaml @@ -14,7 +14,8 @@ services: - './environments/qiita-db-init.sh:/docker-entrypoint-initdb.d/qiita-db-init.sh' - 'postgres-data:/var/lib/postgresql/data' ports: - - "5432:5432" + - "5433:5433" + command: -p 5433 qiita: image: qiita:latest From ee6e1a1d6ef86e48215cb02de2c733dcd0d867d7 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 19 Jun 2024 15:56:40 +0200 Subject: [PATCH 024/287] Address issue #6 to change log directory to dir in repository. All log files are included in the .gitignore! --- .gitignore | 2 ++ compose.yaml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index eb83339..dccbf22 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ environments/*.env +qiita_logs/*log +qiita_logs/*.pid \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index 05e6669..72e120d 100644 --- a/compose.yaml +++ b/compose.yaml @@ -87,7 +87,7 @@ services: volumes: - qiita-data:/qiita - logs:/qiita_logs - + volumes: postgres-data: @@ -102,5 +102,5 @@ volumes: driver_opts: o: bind type: none - device: /tmp/qiita_logs + device: ./qiita_logs From 1aa9d1aef59de246df54cfc6ff59fbe76500f34b Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 19 Jun 2024 15:58:43 +0200 Subject: [PATCH 025/287] Adjust README.md to point out the creation of a qiita_logs folder --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1247153..838340d 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,15 @@ ### Hopefully "foolproof" instructions: 0. Log files will be mounted at /tmp/qiita_logs on your local machine. Make sure the directory exists and is accessible for you. Otherwise, change the file path to your desired path in the compose file as well as in the qiita, nginx and supervisord conf. 1. Clone repository -2. Move into Image Folder `cd Images/qiita` -3. Build docker image `docker build . -f qiita/Dockerfile -t qiita` -4. Build the nginx Image the same way as the qiita image, only in the nginx folder. -5. Move to folder containing compose file `cd ../..` -6. Copy the `qiita_db.env.example` and the `qiita.env.example` 7iles, configure them to your needs, and delete the `.example` from the file names. -7. Run docker compose `docker compose up qiita-db nginx qiita` -8. Open `http://localhost:21174` -9. To stop: Run `docker compose down qiita nginx qiita-db` +2. Add a `qiita_logs` folder to your repository for logging. +3. Move into Image Folder `cd Images/qiita` +4. Build docker image `docker build . -f qiita/Dockerfile -t qiita` +5. Build the nginx Image the same way as the qiita image, only in the nginx folder. +6. Move to folder containing compose file `cd ../..` +7. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. +8. Run docker compose `docker compose up qiita-db nginx qiita` +9. Open `http://localhost:21174` +10. To stop: Run `docker compose down qiita nginx qiita-db` - Use `docker compose down qiita nginx qiita-db --volumes`if you wish to remove all associated volumes as well. Extras: From f644b35721b16986b5c8bc0d0593f08334b463ce Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 19 Jun 2024 15:59:48 +0200 Subject: [PATCH 026/287] Add the configured nginx version to the nginx container image --- Images/nginx/Dockerfile | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/Images/nginx/Dockerfile b/Images/nginx/Dockerfile index 939debd..2d7b039 100644 --- a/Images/nginx/Dockerfile +++ b/Images/nginx/Dockerfile @@ -1,6 +1,8 @@ FROM ubuntu:22.04 ARG MINIFORGE_VERSION=24.1.2-0 +ARG MODZIP_VERSION=1.3.0 +ARG NGINX_VERSION=1.26.0 ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} @@ -8,7 +10,11 @@ ENV PATH=${CONDA_DIR}/bin:${PATH} RUN apt-get -y update RUN apt-get -y install \ git \ - wget + wget \ + libpcre2-dev \ + libxslt-dev \ + libgd-dev \ + libssl-dev RUN apt-get -y install build-essential # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile @@ -17,7 +23,53 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ conda init -RUN conda create --quiet --yes -n nginx nginx +RUN conda create --quiet --yes -n nginx + +SHELL ["conda", "run", "-n", "nginx", "/bin/bash", "-c"] + +RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz +RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz +RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz +RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz +# fix include for the iconv header +RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c +# ensure runtime library paths are correct and openssl headers can be found at compile time +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ + --http-log-path=var/log/nginx/access.log \ + --error-log-path=var/log/nginx/error.log \ + --pid-path=var/run/nginx/nginx.pid \ + --lock-path=var/run/nginx/nginx.lock \ + --http-client-body-temp-path=var/tmp/nginx/client \ + --http-proxy-temp-path=var/tmp/nginx/proxy \ + --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ + --http-scgi-temp-path=var/tmp/nginx/scgi \ + --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ + --sbin-path=sbin/nginx \ + --conf-path=etc/nginx/nginx.conf \ + --modules-path=lib/nginx/modules \ + --with-threads \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_realip_module \ + --with-http_addition_module \ + --with-http_sub_module \ + --with-http_gunzip_module \ + --with-http_gzip_static_module \ + --with-http_auth_request_module \ + --with-http_secure_link_module \ + --with-http_stub_status_module \ + --with-http_xslt_module=dynamic \ + --with-stream=dynamic \ + --with-http_image_filter_module=dynamic \ + --with-pcre \ + --with-pcre-jit \ + --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ + --with-ld-opt="" \ + --prefix=/usr/local \ + --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ + --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install COPY nginx_qiita.conf . COPY start_nginx.sh . From 1a0c8c298a5b76e9066c69b74de615026bba368c Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 19 Jun 2024 17:18:52 +0200 Subject: [PATCH 027/287] Add qtp-biom --- Images/qtp-biom/Dockerfile | 47 +++++++++++++++++++++++++++++++ Images/qtp-biom/start_qtp-biom.sh | 11 ++++++++ compose.yaml | 14 ++++++++- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 Images/qtp-biom/Dockerfile create mode 100644 Images/qtp-biom/start_qtp-biom.sh diff --git a/Images/qtp-biom/Dockerfile b/Images/qtp-biom/Dockerfile new file mode 100644 index 0000000..b26312f --- /dev/null +++ b/Images/qtp-biom/Dockerfile @@ -0,0 +1,47 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc +RUN apt-get -y install build-essential +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ + conda init + +# Download qtp-biom yaml +RUN wget https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml + +# Create conda env +RUN conda env create --quiet -n qtp-biom --file qiime2-2022.11-py38-linux-conda.yml + +# Export cert and config filepaths +RUN export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-n", "qtp-biom", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qtp-biom/archive/master.zip + +RUN pip install --upgrade certifi +RUN pip install pip-system-certs +COPY start_qtp-biom.sh . +RUN chmod 755 start_qtp-biom.sh + +ENTRYPOINT ["conda", "run", "-n", "qtp-biom", "./start_qtp-biom.sh"] \ No newline at end of file diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh new file mode 100644 index 0000000..b62feeb --- /dev/null +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg +export QIITA_PLUGINS_DIR=/qiita/plugins/ + +configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +start_biom https://localhost:8383 register ignored + +#sleep 30000000000000000000000000000 \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index 72e120d..3444260 100644 --- a/compose.yaml +++ b/compose.yaml @@ -87,8 +87,20 @@ services: volumes: - qiita-data:/qiita - logs:/qiita_logs - + qtp-biom: + image: qtp-biom:latest + command: ['./start_qtp-biom.sh'] + network_mode: host + stdin_open: true + tty: true + restart: no + volumes: + - qiita-data:/qiita + depends_on: + - qiita + - qiita-db + volumes: postgres-data: name: qiita-postgres-data From 78c19c4e2da0cd4de62d52c73ac4f5ed3f13d68f Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 19 Jun 2024 17:21:13 +0200 Subject: [PATCH 028/287] Add placeholder file to push qiita_logs folder --- README.md | 17 ++++++++--------- qiita_logs/placeholder.txt | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 qiita_logs/placeholder.txt diff --git a/README.md b/README.md index 838340d..c4675b3 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,14 @@ ### Hopefully "foolproof" instructions: 0. Log files will be mounted at /tmp/qiita_logs on your local machine. Make sure the directory exists and is accessible for you. Otherwise, change the file path to your desired path in the compose file as well as in the qiita, nginx and supervisord conf. 1. Clone repository -2. Add a `qiita_logs` folder to your repository for logging. -3. Move into Image Folder `cd Images/qiita` -4. Build docker image `docker build . -f qiita/Dockerfile -t qiita` -5. Build the nginx Image the same way as the qiita image, only in the nginx folder. -6. Move to folder containing compose file `cd ../..` -7. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. -8. Run docker compose `docker compose up qiita-db nginx qiita` -9. Open `http://localhost:21174` -10. To stop: Run `docker compose down qiita nginx qiita-db` +2. Move into Image Folder `cd Images/qiita` +3. Build docker image `docker build . -f qiita/Dockerfile -t qiita` +4. Build the nginx Image the same way as the qiita image, only in the nginx folder. +5. Move to folder containing compose file `cd ../..` +6. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. +7. Run docker compose `docker compose up qiita-db nginx qiita` +8. Open `http://localhost:21174` +9. To stop: Run `docker compose down qiita nginx qiita-db` - Use `docker compose down qiita nginx qiita-db --volumes`if you wish to remove all associated volumes as well. Extras: diff --git a/qiita_logs/placeholder.txt b/qiita_logs/placeholder.txt new file mode 100644 index 0000000..e9f85fa --- /dev/null +++ b/qiita_logs/placeholder.txt @@ -0,0 +1 @@ +# placeholder so we can push this folder to git \ No newline at end of file From fa200a02734ea94aec41e1c2d44585b65f20f118 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Tue, 20 Aug 2024 09:05:55 +0200 Subject: [PATCH 029/287] Solving merge conflicts --- Images/nginx/nginx_qiita.conf | 10 +++-- Images/nginx/start_nginx.sh | 4 +- Images/qiita/start_qiita.sh | 13 ++++-- README.md | 2 +- compose.yaml | 76 ++++++++++++++++++++--------------- 5 files changed, 63 insertions(+), 42 deletions(-) diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf index ef5478e..dc7c457 100644 --- a/Images/nginx/nginx_qiita.conf +++ b/Images/nginx/nginx_qiita.conf @@ -12,10 +12,10 @@ http { # ports to redirect for mainqiita upstream mainqiita { - server localhost:21174; - server localhost:21175; - server localhost:21176; - server localhost:21177; + server qiita:21174; + server qiita:21175; + server qiita:21176; + server qiita:21177; } # define variables for the actions that shall be taken for websocket handshake @@ -36,6 +36,8 @@ http { server_name _; merge_slashes off; + access_log /qiita_logs/nginx_access_log; + ssl_certificate /qiita/qiita_core/support_files/ci_server.crt; ssl_certificate_key /qiita/qiita_core/support_files/ci_server.key; diff --git a/Images/nginx/start_nginx.sh b/Images/nginx/start_nginx.sh index 0296a80..728f7b7 100644 --- a/Images/nginx/start_nginx.sh +++ b/Images/nginx/start_nginx.sh @@ -1,4 +1,4 @@ #!/bin/bash -mkdir -p /opt/conda/envs/nginx/var/run/nginx/ +mkdir -p /opt/conda/envs/nginx/var/run/nginx/ /usr/local/var/tmp/nginx/ -nginx -c /nginx_qiita.conf \ No newline at end of file +nginx -c /nginx_qiita.conf \ No newline at end of file diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 377db2d..c31ff01 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -6,12 +6,19 @@ redis-server --daemonize yes --port 6379 export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" -conda list +# conda list +if [ "$( psql -XtAc "SELECT 1 FROM postgres WHERE datname='qiita_test'" )" = '1' ] +then + supervisord -c /supervisor_foreground.conf +else + qiita-env make --no-load-ontologies + supervisord -c /supervisor_foreground.conf +fi # building the database without ontologies -qiita-env make --no-load-ontologies # || true +# qiita-env make --no-load-ontologies # || true # starting the webserver without building the docs # qiita pet webserver --no-build-docs start -supervisord -c /supervisor_foreground.conf \ No newline at end of file +# supervisord -c /supervisor_foreground.conf \ No newline at end of file diff --git a/README.md b/README.md index c4675b3..4e8607c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Extras: ### IF YOU WANT TO USE LOCAL KEYCLOAK: 1. Clone repository -2. Run `docker compose up keycloak_web keycloakdb` +2. Run `docker compose up keycloak keycloakdb` 3. Open `http://localhost:8080`, login admin pw admin 4. Configure Qiita as a service, create a user 5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, remove # from necessary oidc block. diff --git a/compose.yaml b/compose.yaml index 3444260..0eff1e0 100644 --- a/compose.yaml +++ b/compose.yaml @@ -3,7 +3,6 @@ services: image: postgres:15 container_name: qiita-db hostname: qiita-db - network_mode: host restart: no env_file: - ./environments/qiita_db.env @@ -13,58 +12,64 @@ services: volumes: - './environments/qiita-db-init.sh:/docker-entrypoint-initdb.d/qiita-db-init.sh' - 'postgres-data:/var/lib/postgresql/data' - ports: - - "5433:5433" - command: -p 5433 + networks: + - qiita-net qiita: - image: qiita:latest + image: local-qiita:latest + build: # image wird hier direkt gebaut + context: ./Images/qiita + dockerfile: Dockerfile command: ['./start_qiita.sh'] # executes bash script inside the container # entrypoint: /bin/bash - stdin_open: true - tty: true - network_mode: host - ports: + # stdin_open: true + # tty: true + # ports: # - "21174:21174" # wihtout nginx - - 8383:8383 + # - 127.0.0.1:8383:8383 #damit bur ich dran komme restart: no depends_on: - qiita-db - - nginx env_file: - './environments/qiita.env' environment: - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt - QIITA_CONFIG_FP=/config_qiita_oidc.cfg volumes: - - qiita-data:/qiita - - logs:/qiita_logs - + - qiita-data:/qiita + - ./qiita_logs:/qiita_logs + - ./Images/qiita/config_qiita_oidc.cfg:/qiita/config_qiita_oidc.cfg + networks: + - qiita-net + # deploy: + # replicas: 3 - keycloak_web: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose + keycloak: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose image: quay.io/keycloak/keycloak:24.0.2 - container_name: keycloak_web + container_name: keycloak environment: KC_DB: postgres KC_DB_URL: jdbc:postgresql://keycloakdb:5432/keycloak KC_DB_USERNAME: keycloak KC_DB_PASSWORD: password - KC_HOSTNAME: localhost + KC_HOSTNAME: keycloak KC_HOSTNAME_PORT: 9999 KC_HOSTNAME_STRICT: false KC_HOSTNAME_STRICT_HTTPS: false KC_LOG_LEVEL: info - KC_METRICS_ENABLED: true + KC_METRICS_ENABLED: false KC_HEALTH_ENABLED: true KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: admin - command: start-dev + command: ["start-dev", "--http-port=9999"] depends_on: - keycloakdb ports: - - 9999:8080 + - 127.0.0.1:9999:9999 + networks: + - qiita-net keycloakdb: image: postgres:15 @@ -74,19 +79,32 @@ services: POSTGRES_DB: keycloak POSTGRES_USER: keycloak POSTGRES_PASSWORD: password + networks: + - qiita-net nginx: - image: nginx_qiita:latest + image: local-nginx_qiita:latest + build: + context: ./Images/nginx + dockerfile: Dockerfile ports: - "8383:8383" command: ['./start_nginx.sh'] - network_mode: host - stdin_open: true - tty: true + # stdin_open: true + # tty: true restart: no + depends_on: + - qiita volumes: - qiita-data:/qiita - - logs:/qiita_logs + - ./nginx_logs:/qiita_logs + - ./Images/nginx/nginx_qiita.conf:/nginx_qiita.conf + networks: + - qiita-net + +networks: + qiita-net: + name: qiita-net qtp-biom: image: qtp-biom:latest @@ -100,6 +118,7 @@ services: depends_on: - qiita - qiita-db + volumes: postgres-data: @@ -108,11 +127,4 @@ volumes: name: keycloak-postgres-data qiita-data: name: qiita-data - logs: - name: logs - driver: local - driver_opts: - o: bind - type: none - device: ./qiita_logs From 891937193706b918eaccda7026f05660e3527bbb Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 31 Jul 2024 12:00:53 +0200 Subject: [PATCH 030/287] Take redis out of qiita image, create own container --- Images/qiita/Dockerfile | 10 +++++----- Images/qiita/start_qiita.sh | 6 +++--- compose.yaml | 14 +++++++++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index bdd2fa7..0f7c44c 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -29,7 +29,7 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ # create conda env for qiita with all necessary dependencies (conda and pip) RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy cython anaconda::redis - +# TODO: Redis container # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-n", "qiita", "/bin/bash", "-c"] @@ -103,12 +103,12 @@ RUN pip install -e qiita --no-binary redbiom # Copy modified config file to the container -COPY config_qiita_oidc.cfg /qiita/ -RUN chmod 755 /qiita/config_qiita_oidc.cfg +# COPY config_qiita_oidc.cfg /qiita/ +# RUN chmod 755 /qiita/config_qiita_oidc.cfg # Copy Bash Script to run Qiita to the container -COPY start_qiita.sh . -RUN chmod 755 start_qiita.sh +# COPY start_qiita.sh . +# RUN chmod 755 start_qiita.sh COPY supervisor_foreground.conf . RUN chmod 755 supervisor_foreground.conf diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index c31ff01..c815fd5 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -1,11 +1,11 @@ #!/bin/bash # first we start the redis server -redis-server --daemonize yes --port 7777 -redis-server --daemonize yes --port 6379 +# redis-server --daemonize yes --port 7777 +# redis-server --daemonize yes --port 6379 export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" - +# TODO: kick out the supervisor -> one "master" image and one "worker" image and then they do shenanigans together via replicas # conda list if [ "$( psql -XtAc "SELECT 1 FROM postgres WHERE datname='qiita_test'" )" = '1' ] then diff --git a/compose.yaml b/compose.yaml index 0eff1e0..0edc6f0 100644 --- a/compose.yaml +++ b/compose.yaml @@ -30,6 +30,7 @@ services: restart: no depends_on: - qiita-db + - redis env_file: - './environments/qiita.env' environment: @@ -39,11 +40,22 @@ services: - qiita-data:/qiita - ./qiita_logs:/qiita_logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita/config_qiita_oidc.cfg + - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh networks: - qiita-net # deploy: # replicas: 3 - + redis: + image: redis:latest + restart: no + command: > + sh -c "redis-server --port 7777 && + redis-server --port 6379" + volumes: + - qiita-data:/qiita + - ./qiita_logs:/qiita_logs + networks: + - qiita-net keycloak: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose image: quay.io/keycloak/keycloak:24.0.2 container_name: keycloak From 02bcc367a3e3f7e287016113a5b49761bcb19cfc Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 31 Jul 2024 14:57:30 +0200 Subject: [PATCH 031/287] Remove Supervisord, use qiita_worker service instead --- Images/qiita/Dockerfile | 88 +++++++++++++++--------------- Images/qiita/start_qiita.sh | 6 +- Images/qiita/start_qiita_worker.sh | 7 +++ compose.yaml | 30 ++++++++++ 4 files changed, 85 insertions(+), 46 deletions(-) create mode 100644 Images/qiita/start_qiita_worker.sh diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 0f7c44c..4447e7c 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -43,50 +43,50 @@ RUN pip install \ coverage \ psycopg2-binary -# manually compile nginx to enable mod_zip -RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz -RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz -RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz -RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz -# fix include for the iconv header -RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c -# ensure runtime library paths are correct and openssl headers can be found at compile time -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ - --http-log-path=var/log/nginx/access.log \ - --error-log-path=var/log/nginx/error.log \ - --pid-path=var/run/nginx/nginx.pid \ - --lock-path=var/run/nginx/nginx.lock \ - --http-client-body-temp-path=var/tmp/nginx/client \ - --http-proxy-temp-path=var/tmp/nginx/proxy \ - --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ - --http-scgi-temp-path=var/tmp/nginx/scgi \ - --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ - --sbin-path=sbin/nginx \ - --conf-path=etc/nginx/nginx.conf \ - --modules-path=lib/nginx/modules \ - --with-threads \ - --with-http_ssl_module \ - --with-http_v2_module \ - --with-http_realip_module \ - --with-http_addition_module \ - --with-http_sub_module \ - --with-http_gunzip_module \ - --with-http_gzip_static_module \ - --with-http_auth_request_module \ - --with-http_secure_link_module \ - --with-http_stub_status_module \ - --with-http_xslt_module=dynamic \ - --with-stream=dynamic \ - --with-http_image_filter_module=dynamic \ - --with-pcre \ - --with-pcre-jit \ - --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ - --with-ld-opt="" \ - --prefix=/usr/local \ - --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ - --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install +# # manually compile nginx to enable mod_zip +# RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz +# RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz +# RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz +# RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz +# # fix include for the iconv header +# RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c +# # ensure runtime library paths are correct and openssl headers can be found at compile time +# RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ +# --http-log-path=var/log/nginx/access.log \ +# --error-log-path=var/log/nginx/error.log \ +# --pid-path=var/run/nginx/nginx.pid \ +# --lock-path=var/run/nginx/nginx.lock \ +# --http-client-body-temp-path=var/tmp/nginx/client \ +# --http-proxy-temp-path=var/tmp/nginx/proxy \ +# --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ +# --http-scgi-temp-path=var/tmp/nginx/scgi \ +# --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ +# --sbin-path=sbin/nginx \ +# --conf-path=etc/nginx/nginx.conf \ +# --modules-path=lib/nginx/modules \ +# --with-threads \ +# --with-http_ssl_module \ +# --with-http_v2_module \ +# --with-http_realip_module \ +# --with-http_addition_module \ +# --with-http_sub_module \ +# --with-http_gunzip_module \ +# --with-http_gzip_static_module \ +# --with-http_auth_request_module \ +# --with-http_secure_link_module \ +# --with-http_stub_status_module \ +# --with-http_xslt_module=dynamic \ +# --with-stream=dynamic \ +# --with-http_image_filter_module=dynamic \ +# --with-pcre \ +# --with-pcre-jit \ +# --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ +# --with-ld-opt="" \ +# --prefix=/usr/local \ +# --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ +# --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " +# RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make +# RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install #cClone the Qiita Repo # RUN git clone -b master https://github.com/qiita-spots/qiita.git diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index c815fd5..6e79bab 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -9,10 +9,12 @@ export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" # conda list if [ "$( psql -XtAc "SELECT 1 FROM postgres WHERE datname='qiita_test'" )" = '1' ] then - supervisord -c /supervisor_foreground.conf + # supervisord -c /supervisor_foreground.conf + qiita pet webserver --no-build-docs start --port 21174 --master else qiita-env make --no-load-ontologies - supervisord -c /supervisor_foreground.conf + qiita pet webserver --no-build-docs start --port 21174 --master + # supervisord -c /supervisor_foreground.conf fi # building the database without ontologies diff --git a/Images/qiita/start_qiita_worker.sh b/Images/qiita/start_qiita_worker.sh new file mode 100644 index 0000000..8316b9c --- /dev/null +++ b/Images/qiita/start_qiita_worker.sh @@ -0,0 +1,7 @@ +#!/bin/bash + + +export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" + +qiita pet webserver --no-build-docs start --port 21175 + diff --git a/compose.yaml b/compose.yaml index 0edc6f0..9a00dfe 100644 --- a/compose.yaml +++ b/compose.yaml @@ -45,6 +45,36 @@ services: - qiita-net # deploy: # replicas: 3 + qiita_worker: + image: local-qiita:latest + build: # image wird hier direkt gebaut + context: ./Images/qiita + dockerfile: Dockerfile + command: ['./start_qiita_worker.sh'] # executes bash script inside the container + # entrypoint: /bin/bash + # stdin_open: true + # tty: true + # ports: + # - "21174:21174" # wihtout nginx + # - 127.0.0.1:8383:8383 #damit bur ich dran komme + restart: no + depends_on: + - qiita-db + - redis + - qiita + env_file: + - './environments/qiita.env' + environment: + - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt + - QIITA_CONFIG_FP=/config_qiita_oidc.cfg + volumes: + - qiita-data:/qiita + - ./qiita_logs:/qiita_logs + - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh + networks: + - qiita-net + deploy: + replicas: 3 redis: image: redis:latest restart: no From fd9410a3627055d162b08f498a1c74c54a7b7608 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 8 Aug 2024 10:14:13 +0200 Subject: [PATCH 032/287] Fixed Previous Commits, Redis can now communicate with Qiita and Qiita without supervisord works as intended. --- Images/nginx/nginx_qiita.conf | 6 +-- Images/qiita/Dockerfile | 62 ++++++------------------------ Images/qiita/config_qiita_oidc.cfg | 6 +-- Images/qiita/start_qiita.sh | 21 ++-------- Images/qiita/start_qiita_worker.sh | 0 compose.yaml | 5 ++- 6 files changed, 23 insertions(+), 77 deletions(-) mode change 100644 => 100755 Images/qiita/start_qiita_worker.sh diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf index dc7c457..426c3e2 100644 --- a/Images/nginx/nginx_qiita.conf +++ b/Images/nginx/nginx_qiita.conf @@ -13,9 +13,9 @@ http { # ports to redirect for mainqiita upstream mainqiita { server qiita:21174; - server qiita:21175; - server qiita:21176; - server qiita:21177; + server qiita_worker:21175; + server qiita_worker:21176; + server qiita_worker:21177; } # define variables for the actions that shall be taken for websocket handshake diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 4447e7c..678a60e 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -17,7 +17,8 @@ RUN apt-get -y --fix-missing install \ gcc \ libpcre2-dev \ libxslt-dev \ - libgd-dev + libgd-dev \ + postgresql-client RUN apt-get -y install build-essential # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile @@ -43,52 +44,8 @@ RUN pip install \ coverage \ psycopg2-binary -# # manually compile nginx to enable mod_zip -# RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz -# RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz -# RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz -# RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz -# # fix include for the iconv header -# RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c -# # ensure runtime library paths are correct and openssl headers can be found at compile time -# RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ -# --http-log-path=var/log/nginx/access.log \ -# --error-log-path=var/log/nginx/error.log \ -# --pid-path=var/run/nginx/nginx.pid \ -# --lock-path=var/run/nginx/nginx.lock \ -# --http-client-body-temp-path=var/tmp/nginx/client \ -# --http-proxy-temp-path=var/tmp/nginx/proxy \ -# --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ -# --http-scgi-temp-path=var/tmp/nginx/scgi \ -# --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ -# --sbin-path=sbin/nginx \ -# --conf-path=etc/nginx/nginx.conf \ -# --modules-path=lib/nginx/modules \ -# --with-threads \ -# --with-http_ssl_module \ -# --with-http_v2_module \ -# --with-http_realip_module \ -# --with-http_addition_module \ -# --with-http_sub_module \ -# --with-http_gunzip_module \ -# --with-http_gzip_static_module \ -# --with-http_auth_request_module \ -# --with-http_secure_link_module \ -# --with-http_stub_status_module \ -# --with-http_xslt_module=dynamic \ -# --with-stream=dynamic \ -# --with-http_image_filter_module=dynamic \ -# --with-pcre \ -# --with-pcre-jit \ -# --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ -# --with-ld-opt="" \ -# --prefix=/usr/local \ -# --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ -# --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " -# RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make -# RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install -#cClone the Qiita Repo +# Clone the Qiita Repo # RUN git clone -b master https://github.com/qiita-spots/qiita.git RUN git clone -b auth_oidc https://github.com/jlab/qiita.git @@ -103,12 +60,15 @@ RUN pip install -e qiita --no-binary redbiom # Copy modified config file to the container -# COPY config_qiita_oidc.cfg /qiita/ -# RUN chmod 755 /qiita/config_qiita_oidc.cfg + COPY config_qiita_oidc.cfg /qiita/ + RUN chmod 755 /qiita/config_qiita_oidc.cfg # Copy Bash Script to run Qiita to the container -# COPY start_qiita.sh . -# RUN chmod 755 start_qiita.sh + COPY start_qiita.sh . + RUN chmod 755 start_qiita.sh + + COPY start_qiita_worker.sh . + RUN chmod 755 start_qiita_worker.sh COPY supervisor_foreground.conf . RUN chmod 755 supervisor_foreground.conf @@ -116,4 +76,4 @@ RUN chmod 755 supervisor_foreground.conf # I will leave this ENTRYPOINT here as a comment in case debugging # is necessary # SHELL ["/bin/bash"] -ENTRYPOINT ["conda", "run", "-n", "qiita", "./start_qiita.sh"] \ No newline at end of file +ENTRYPOINT ["conda", "run", "-n", "qiita"] \ No newline at end of file diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index 4959e2a..17e466f 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -99,7 +99,7 @@ EMAIL = example@domain.com # ----------------------------- Redis settings -------------------------------- [redis] -HOST = localhost +HOST = redis PORT = 7777 PASSWORD = # The redis database you will use, redis has a max of 16. @@ -118,10 +118,10 @@ ADMIN_USER = postgres DATABASE = qiita_test # The host where the database lives on -HOST = localhost +HOST = qiita-db # The port to connect to the database -PORT = 5433 +PORT = 5432 # The password to use to connect to the database PASSWORD = postgres diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 6e79bab..7cf8e42 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -1,26 +1,11 @@ #!/bin/bash - -# first we start the redis server -# redis-server --daemonize yes --port 7777 -# redis-server --daemonize yes --port 6379 - +#sleep 300000 export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" -# TODO: kick out the supervisor -> one "master" image and one "worker" image and then they do shenanigans together via replicas -# conda list -if [ "$( psql -XtAc "SELECT 1 FROM postgres WHERE datname='qiita_test'" )" = '1' ] + +if [ "$( psql -h localhost -U postgres -XtAc "SELECT 1 FROM postgres WHERE datname='qiita_test'" )" = '1' ] then - # supervisord -c /supervisor_foreground.conf qiita pet webserver --no-build-docs start --port 21174 --master else qiita-env make --no-load-ontologies qiita pet webserver --no-build-docs start --port 21174 --master - # supervisord -c /supervisor_foreground.conf fi - -# building the database without ontologies -# qiita-env make --no-load-ontologies # || true - -# starting the webserver without building the docs -# qiita pet webserver --no-build-docs start - -# supervisord -c /supervisor_foreground.conf \ No newline at end of file diff --git a/Images/qiita/start_qiita_worker.sh b/Images/qiita/start_qiita_worker.sh old mode 100644 new mode 100755 diff --git a/compose.yaml b/compose.yaml index 9a00dfe..88d4b2d 100644 --- a/compose.yaml +++ b/compose.yaml @@ -40,7 +40,7 @@ services: - qiita-data:/qiita - ./qiita_logs:/qiita_logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita/config_qiita_oidc.cfg - - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh + # - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh networks: - qiita-net # deploy: @@ -70,7 +70,8 @@ services: volumes: - qiita-data:/qiita - ./qiita_logs:/qiita_logs - - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh + - ./Images/qiita/config_qiita_oidc.cfg:/qiita/config_qiita_oidc.cfg + # - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh networks: - qiita-net deploy: From 452a129489241f99ecc3439972fd7c3c25662b8d Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 8 Aug 2024 10:22:29 +0200 Subject: [PATCH 033/287] Expand Readme --- README.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4e8607c..1946766 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,16 @@ **FOR TESTING ON LOCAL MACHINES** ### Hopefully "foolproof" instructions: -0. Log files will be mounted at /tmp/qiita_logs on your local machine. Make sure the directory exists and is accessible for you. Otherwise, change the file path to your desired path in the compose file as well as in the qiita, nginx and supervisord conf. +0. Log files will be mounted at qiita_logs on your local machine in this repo directory. Otherwise, change the file path to your desired path in the compose file as well as in the qiita, nginx and supervisord conf. 1. Clone repository 2. Move into Image Folder `cd Images/qiita` -3. Build docker image `docker build . -f qiita/Dockerfile -t qiita` -4. Build the nginx Image the same way as the qiita image, only in the nginx folder. +3. Build docker image `docker build . -f qiita/Dockerfile -t local-qiita` +4. Build the nginx Image the same way as the qiita image, only in the nginx folder, using the image tag `local-nginx_qiita`. 5. Move to folder containing compose file `cd ../..` 6. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. -7. Run docker compose `docker compose up qiita-db nginx qiita` -8. Open `http://localhost:21174` -9. To stop: Run `docker compose down qiita nginx qiita-db` +7. Run docker compose `docker compose up qiita-db redis nginx qiita` +8. Open `http://localhost:8383` +9. To stop: Run `docker compose down qiita nginx qiita-db redis` - Use `docker compose down qiita nginx qiita-db --volumes`if you wish to remove all associated volumes as well. Extras: @@ -27,8 +27,15 @@ Extras: 4. Configure Qiita as a service, create a user 5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, remove # from necessary oidc block. 6. Open a new terminal, move into Image Folder `cd Images/qiita` -7. Build docker image `docker build . -f qiita/Dockerfile -t qiita` +7. Build docker image for qiita and nginx according to steps 3 and 4 from the instructions above. 8. Move to folder containing compose file `cd ../..` 9. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. -10. Run docker compose `docker compose up qiita qiita-db` -11. Open `http://localhost:21174` \ No newline at end of file +10. Run docker compose `docker compose up qiita qiita-db redis nginx` +11. Open `http://localhost:8383` + +### IF YOU WANT TO RUN MULTIPLE INSTANCES WITHOUT SUPERVISORD + +1. Perform all the steps listed in the keycloak instructions until you arrive at step 10 +2. Check the amount of replicas you desire for your run in the compose file. +3. Run docker compose with `docker compose up qiita qiita-db redis qiita_worker nginx` +4. Open `http://localhost:8383` From 29da82c69ee7933da516679e27f0d5672ffd3f19 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Tue, 20 Aug 2024 09:11:50 +0200 Subject: [PATCH 034/287] Fix error from. solving merge requests --- compose.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compose.yaml b/compose.yaml index 88d4b2d..3f8ab96 100644 --- a/compose.yaml +++ b/compose.yaml @@ -144,11 +144,7 @@ services: - ./Images/nginx/nginx_qiita.conf:/nginx_qiita.conf networks: - qiita-net - -networks: - qiita-net: - name: qiita-net - + qtp-biom: image: qtp-biom:latest command: ['./start_qtp-biom.sh'] @@ -162,6 +158,10 @@ networks: - qiita - qiita-db +networks: + qiita-net: + name: qiita-net + volumes: postgres-data: From b9da47115163059f7dfa9bac5add247d3deddfb3 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 5 Feb 2025 10:31:50 +0100 Subject: [PATCH 035/287] Add ugly intermediate code to workshop together --- .gitignore | 3 +- Images/qiita/Dockerfile | 6 --- Images/qiita/config_qiita_oidc.cfg | 68 +++++++++++++++--------------- Images/qiita/start_qiita.sh | 18 +++++--- Images/qtp-biom/Dockerfile | 4 ++ Images/qtp-biom/start_qtp-biom.sh | 9 ++-- compose.yaml | 12 ++++-- nginx_logs/placeholder.txt | 0 8 files changed, 65 insertions(+), 55 deletions(-) create mode 100644 nginx_logs/placeholder.txt diff --git a/.gitignore b/.gitignore index dccbf22..9b8feb7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ environments/*.env qiita_logs/*log -qiita_logs/*.pid \ No newline at end of file +qiita_logs/*.pid +nginx_logs/*_log \ No newline at end of file diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile index 678a60e..9359ba5 100644 --- a/Images/qiita/Dockerfile +++ b/Images/qiita/Dockerfile @@ -70,10 +70,4 @@ RUN pip install -e qiita --no-binary redbiom COPY start_qiita_worker.sh . RUN chmod 755 start_qiita_worker.sh -COPY supervisor_foreground.conf . -RUN chmod 755 supervisor_foreground.conf - -# I will leave this ENTRYPOINT here as a comment in case debugging -# is necessary -# SHELL ["/bin/bash"] ENTRYPOINT ["conda", "run", "-n", "qiita"] \ No newline at end of file diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index 17e466f..de0ffdd 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -228,38 +228,38 @@ QIIMP = https://localhost:8898/ # # To activate IdP: comment out the following config section -# [oidc_localkeycloak] -# -## client ID for Qiita as registered at your Identity Provider of choice -# CLIENT_ID = qiita -# -## client secret to verify Qiita as the correct client. Not all IdPs require -## a client secret! -# CLIENT_SECRET = supersecretString +[oidc_localkeycloak] -# -## redirect URL (end point in your Qiita instance), to which the IdP redirects -## after user types in his/her credentials. If you don't want to change code in -## qiita_pet/webserver.py the URL must follow the pattern: -## base_URL/auth/login_OIDC/foo where foo is the name of this config section -## without the oidc_ prefix! -# REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak -# -## The URL of the well-known json document, specifying how API end points -## like 'authorize', 'token' or 'userinfo' are defined. See e.g. -## https://swagger.io/docs/specification/authentication/ -## openid-connect-discovery/ -# WELLKNOWN_URI = http://localhost:9999/realms/qiita_realm/.well-known/openid-configuration -# -## a speaking label for the Identity Provider. Section name is used if empty. -# LABEL = localkeycloak -# -## The scope, i.e. fields about a user, which Qiita requests from the -## Identity Provider, e.g. "profile email eduperson_orcid". -## Will be automatically extended by the scope "openid", to enable the -## "authorize_code" OIDC flow. -# SCOPE = openid -# -##Optional. Name of a file in qiita_pet/static/img that shall be -##displayed for login through Service Provider, instead of a plain button -# LOGO = +# client ID for Qiita as registered at your Identity Provider of choice + CLIENT_ID = qiita + +# client secret to verify Qiita as the correct client. Not all IdPs require +# a client secret! + CLIENT_SECRET = SUPERSECRETSTRING + + +# redirect URL (end point in your Qiita instance), to which the IdP redirects +# after user types in his/her credentials. If you don't want to change code in +# qiita_pet/webserver.py the URL must follow the pattern: +# base_URL/auth/login_OIDC/foo where foo is the name of this config section +# without the oidc_ prefix! + REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak + +# The URL of the well-known json document, specifying how API end points +# like 'authorize', 'token' or 'userinfo' are defined. See e.g. +# https://swagger.io/docs/specification/authentication/ +# openid-connect-discovery/ + WELLKNOWN_URI = http://keycloak:9999/realms/qiita_realm/.well-known/openid-configuration/ + +# a speaking label for the Identity Provider. Section name is used if empty. + LABEL = localkeycloak + +# The scope, i.e. fields about a user, which Qiita requests from the +# Identity Provider, e.g. "profile email eduperson_orcid". +# Will be automatically extended by the scope "openid", to enable the +# "authorize_code" OIDC flow. + SCOPE = openid + +#Optional. Name of a file in qiita_pet/static/img that shall be +#displayed for login through Service Provider, instead of a plain button + LOGO = diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 7cf8e42..8b79a4d 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -2,10 +2,14 @@ #sleep 300000 export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" -if [ "$( psql -h localhost -U postgres -XtAc "SELECT 1 FROM postgres WHERE datname='qiita_test'" )" = '1' ] -then - qiita pet webserver --no-build-docs start --port 21174 --master -else - qiita-env make --no-load-ontologies - qiita pet webserver --no-build-docs start --port 21174 --master -fi +# This was commented out bc it stopped working anymore and i was focusing on fixing something else, if you create the database for the first +# time you will have to pick the appropriate options. +#if [ "$( export PGPASSWORD='postgres'; psql -h qiita-db -U postgres -XtAc "SELECT 1 FROM postgres WHERE datname='qiita_test'" )" = '1' ] +#then +# qiita pet webserver --no-build-docs start --port 21174 --master +#else +# qiita-env make --no-load-ontologies +# qiita pet webserver --no-build-docs start --port 21174 --master +#fi +#qiita-env make --no-load-ontologies +qiita pet webserver --no-build-docs start --port 21174 --master \ No newline at end of file diff --git a/Images/qtp-biom/Dockerfile b/Images/qtp-biom/Dockerfile index b26312f..c5c059c 100644 --- a/Images/qtp-biom/Dockerfile +++ b/Images/qtp-biom/Dockerfile @@ -38,9 +38,13 @@ SHELL ["conda", "run", "-n", "qtp-biom", "/bin/bash", "-c"] RUN pip install -U pip RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip RUN pip install https://github.com/qiita-spots/qtp-biom/archive/master.zip +RUN git clone https://github.com/qiita-spots/qtp-biom.git RUN pip install --upgrade certifi RUN pip install pip-system-certs + +RUN sed -i 's/2.1.4 - Qiime2/2.1.5 - Qiime2 Annas Version/g' /qtp-biom/qtp_biom/__init__.py + COPY start_qtp-biom.sh . RUN chmod 755 start_qtp-biom.sh diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index b62feeb..21d5b40 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -4,8 +4,11 @@ export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg export QIITA_PLUGINS_DIR=/qiita/plugins/ -configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) -start_biom https://localhost:8383 register ignored +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT -#sleep 30000000000000000000000000000 \ No newline at end of file +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored + +sleep 30000000000000000 \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index 3f8ab96..859be81 100644 --- a/compose.yaml +++ b/compose.yaml @@ -146,21 +146,25 @@ services: - qiita-net qtp-biom: - image: qtp-biom:latest + image: local-qtp-biom:latest command: ['./start_qtp-biom.sh'] - network_mode: host - stdin_open: true - tty: true + # network_mode: host + # stdin_open: true + # tty: true restart: no volumes: - qiita-data:/qiita depends_on: - qiita - qiita-db + - qiita_worker + networks: + - qiita-net networks: qiita-net: name: qiita-net + external: true volumes: diff --git a/nginx_logs/placeholder.txt b/nginx_logs/placeholder.txt new file mode 100644 index 0000000..e69de29 From eea8d6d875bc45feefa8cc233527029a6350bc8a Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Wed, 5 Feb 2025 10:46:45 +0100 Subject: [PATCH 036/287] Change Readme --- README.md | 44 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 1946766..c828284 100644 --- a/README.md +++ b/README.md @@ -6,36 +6,16 @@ 0. Log files will be mounted at qiita_logs on your local machine in this repo directory. Otherwise, change the file path to your desired path in the compose file as well as in the qiita, nginx and supervisord conf. 1. Clone repository 2. Move into Image Folder `cd Images/qiita` -3. Build docker image `docker build . -f qiita/Dockerfile -t local-qiita` +3. Build docker image `sudo docker build . -f qiita/Dockerfile -t local-qiita` 4. Build the nginx Image the same way as the qiita image, only in the nginx folder, using the image tag `local-nginx_qiita`. -5. Move to folder containing compose file `cd ../..` -6. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. -7. Run docker compose `docker compose up qiita-db redis nginx qiita` -8. Open `http://localhost:8383` -9. To stop: Run `docker compose down qiita nginx qiita-db redis` - - Use `docker compose down qiita nginx qiita-db --volumes`if you wish to remove all associated volumes as well. - -Extras: -- If you want to remove a specific volume `docker volume rm ` -- If you want to access a container `docker ps`to fetch the ID and `docker exec -it bash` - -### IF YOU WANT TO USE LOCAL KEYCLOAK: - -1. Clone repository -2. Run `docker compose up keycloak keycloakdb` -3. Open `http://localhost:8080`, login admin pw admin -4. Configure Qiita as a service, create a user -5. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, remove # from necessary oidc block. -6. Open a new terminal, move into Image Folder `cd Images/qiita` -7. Build docker image for qiita and nginx according to steps 3 and 4 from the instructions above. -8. Move to folder containing compose file `cd ../..` -9. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. -10. Run docker compose `docker compose up qiita qiita-db redis nginx` -11. Open `http://localhost:8383` - -### IF YOU WANT TO RUN MULTIPLE INSTANCES WITHOUT SUPERVISORD - -1. Perform all the steps listed in the keycloak instructions until you arrive at step 10 -2. Check the amount of replicas you desire for your run in the compose file. -3. Run docker compose with `docker compose up qiita qiita-db redis qiita_worker nginx` -4. Open `http://localhost:8383` +5. Repeat with qtp-biom Image as `local-qtp-biom`. +6. Move to folder containing compose file `cd ../..` +7. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. +8. Run `sudo docker compose up keycloak keycloakdb` +9. Open `http://localhost:8080`, login admin pw admin +10. Configure Qiita as a service, create a user. +11. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, remove # from necessary oidc block, change SUPERSECRETSTRING. +12. Run docker compose `sudo docker compose up qiita qiita-db redis qiita_worker nginx` +- Due to some unforseen problem I did not want to deal with, yet, the original "database existence" check does not work anymore. You might have to adjust the command in start_qiita.sh the first time you run it to create your database :/ +13. You can access the relevant containers by checking for their names with `sudo docker container ls` and then running `sudo docker exec -it bash` +14. Open `http://localhost:8383` From eddccf991c96999b36d366573a76ea04b1ff2905 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:31:20 +0100 Subject: [PATCH 037/287] use different log dirs AND address worker by docker container names --- Images/nginx/nginx_qiita.conf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf index 426c3e2..537cd54 100644 --- a/Images/nginx/nginx_qiita.conf +++ b/Images/nginx/nginx_qiita.conf @@ -1,21 +1,21 @@ -user nobody nogroup; +user nobody nogroup; daemon off; # error_log /var/log/nginx/error_log warn; -error_log /qiita_logs/nginx_error_log warn; +error_log /logs/nginx_error.log warn; events { worker_connections 1024; } http { - client_max_body_size 7M; # increase maximum body size from default 1M to match https://github.com/qiita-spots/qiita/blob/ac62aba5333f537c32e213855edc39c273aa9871/qiita_pet/static/vendor/js/resumable-uploader.js#L51 (which is 3M). Note that resumable-uploader.js's last chunk can be max. twice as large as chunk size, see: https://github.com/23/resumable.js/issues/51 + client_max_body_size 7M; # increase maximum body size from default 1M to match https://github.com/qiita-spots/qiita/blob/ac62aba5333f537c32e213855edc39c273aa9871/qiita_pet/static/vendor/js/resumable-uploader.js#L51 (which is 3M). Note that resumable-uploader.js's last chunk can be max. twice as large as chunk size, see: https://github.com/23/resumable.js/issues/51 # ports to redirect for mainqiita upstream mainqiita { server qiita:21174; - server qiita_worker:21175; - server qiita_worker:21176; - server qiita_worker:21177; + server qiita_container_anna-qiita_worker-2:21175; + server qiita_container_anna-qiita_worker-2:21175; + server qiita_container_anna-qiita_worker-2:21175; } # define variables for the actions that shall be taken for websocket handshake @@ -36,7 +36,7 @@ http { server_name _; merge_slashes off; - access_log /qiita_logs/nginx_access_log; + access_log /logs/nginx_access.log; ssl_certificate /qiita/qiita_core/support_files/ci_server.crt; ssl_certificate_key /qiita/qiita_core/support_files/ci_server.key; From 489974bc15720a0f08ae195af25a60772b089020 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:31:48 +0100 Subject: [PATCH 038/287] expect config in different path --- Images/nginx/start_nginx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/nginx/start_nginx.sh b/Images/nginx/start_nginx.sh index 728f7b7..a95a1a1 100644 --- a/Images/nginx/start_nginx.sh +++ b/Images/nginx/start_nginx.sh @@ -1,4 +1,4 @@ #!/bin/bash mkdir -p /opt/conda/envs/nginx/var/run/nginx/ /usr/local/var/tmp/nginx/ -nginx -c /nginx_qiita.conf \ No newline at end of file +nginx -c /qiita_configuration/nginx_qiita.conf From 7928b415348eecd325c9561330ac3c5db9050256 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:32:09 +0100 Subject: [PATCH 039/287] be more flexible with CMD instead of fixed ENTRYPOINT --- Images/nginx/nginx.dockerfile | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Images/nginx/nginx.dockerfile diff --git a/Images/nginx/nginx.dockerfile b/Images/nginx/nginx.dockerfile new file mode 100644 index 0000000..9b5a51f --- /dev/null +++ b/Images/nginx/nginx.dockerfile @@ -0,0 +1,83 @@ +FROM ubuntu:22.04 + +ARG MINIFORGE_VERSION=24.1.2-0 +ARG MODZIP_VERSION=1.3.0 +ARG NGINX_VERSION=1.26.0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y install \ + git \ + wget \ + libpcre2-dev \ + libxslt-dev \ + libgd-dev \ + libssl-dev +RUN apt-get -y install build-essential +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ + conda init +RUN conda create --quiet --yes -n nginx + +SHELL ["conda", "run", "-n", "nginx", "/bin/bash", "-c"] + +RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz +RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz +RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz +RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz +# fix include for the iconv header +RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c +# ensure runtime library paths are correct and openssl headers can be found at compile time +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ + --http-log-path=var/log/nginx/access.log \ + --error-log-path=var/log/nginx/error.log \ + --pid-path=var/run/nginx/nginx.pid \ + --lock-path=var/run/nginx/nginx.lock \ + --http-client-body-temp-path=var/tmp/nginx/client \ + --http-proxy-temp-path=var/tmp/nginx/proxy \ + --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ + --http-scgi-temp-path=var/tmp/nginx/scgi \ + --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ + --sbin-path=sbin/nginx \ + --conf-path=etc/nginx/nginx.conf \ + --modules-path=lib/nginx/modules \ + --with-threads \ + --with-http_ssl_module \ + --with-http_v2_module \ + --with-http_realip_module \ + --with-http_addition_module \ + --with-http_sub_module \ + --with-http_gunzip_module \ + --with-http_gzip_static_module \ + --with-http_auth_request_module \ + --with-http_secure_link_module \ + --with-http_stub_status_module \ + --with-http_xslt_module=dynamic \ + --with-stream=dynamic \ + --with-http_image_filter_module=dynamic \ + --with-pcre \ + --with-pcre-jit \ + --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ + --with-ld-opt="" \ + --prefix=/usr/local \ + --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ + --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make -j 10 +RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install + +COPY nginx_qiita.conf . +COPY start_nginx.sh . + +RUN chmod 777 nginx_qiita.conf +RUN chmod 777 start_nginx.sh + +RUN mkdir /var/log/nginx + +#ENTRYPOINT ["/bin/bash", "-l", "-c" ] +CMD ["conda", "run", "-n", "nginx", "./start_nginx.sh"] \ No newline at end of file From ed9c1ba9d49b50e3f4bada99bf5c606e93189844 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:33:40 +0100 Subject: [PATCH 040/287] also install my trigger server --- Images/qtp-biom/qtp-biom.dockerfile | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Images/qtp-biom/qtp-biom.dockerfile diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile new file mode 100644 index 0000000..a4715b3 --- /dev/null +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -0,0 +1,61 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# Download qtp-biom yaml +RUN wget https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml + +# Create conda env +RUN conda env create --quiet -n qtp-biom --file qiime2-2022.11-py38-linux-conda.yml +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone https://github.com/qiita-spots/qtp-biom.git +WORKDIR qtp-biom +RUN pip install -e . +RUN pip install --upgrade certifi +RUN pip install pip-system-certs +RUN conda install tornado +COPY trigger.py /trigger.py + +## Export cert and config filepaths +RUN export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qtp-biom.sh . +RUN chmod 755 start_qtp-biom.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +RUN /qtp-biom/scripts/configure_biom --env-script "source /home/joe/.bashrc; conda activate env_deblur" --server-cert /qiita/qiita_core/support_files/ci_rootca.crt + + +CMD ["conda", "run", "-n", "qtp-biom", "./start_qtp-biom.sh"] \ No newline at end of file From 7eb06354e9acf217c515641b6aeb5d6d4f8cf18e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:34:32 +0100 Subject: [PATCH 041/287] start upo trigger.py and wait for incoming connections --- Images/qtp-biom/start_qtp-biom.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index 21d5b40..085cfdd 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -1,8 +1,9 @@ #!/bin/bash export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg -export QIITA_PLUGINS_DIR=/qiita/plugins/ +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qtp-biom # Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) @@ -10,5 +11,7 @@ export QIITA_PLUGINS_DIR=/qiita/plugins/ #start_biom https://localhost:8383 register ignored #start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-biom; cd / && python trigger.py -sleep 30000000000000000 \ No newline at end of file +tail -f /dev/null From 129da2306c7b27da163c94b22ff2377e0b97e022 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:35:31 +0100 Subject: [PATCH 042/287] deactivate keycloak for now --- Images/qiita/config_qiita_oidc.cfg | 75 +++++++++++++++--------------- Images/qiita/qiita.dockerfile | 74 +++++++++++++++++++++++++++++ Images/qiita/start_qiita.sh | 19 ++++++-- 3 files changed, 128 insertions(+), 40 deletions(-) create mode 100644 Images/qiita/qiita.dockerfile diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index de0ffdd..dd596d3 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -17,7 +17,7 @@ TEST_ENVIRONMENT = TRUE # Absolute path to the directory where log files are saved. If not given, no # log file will be created -LOG_DIR = /qiita_logs/ +LOG_DIR = /logs/ # Whether studies require admin approval to be made available REQUIRE_APPROVAL = True @@ -51,7 +51,7 @@ PRIVATE_LAUNCHER = qiita-private-launcher PLUGIN_LAUNCHER = qiita-plugin-launcher # Plugins configuration directory -PLUGIN_DIR = /qiita/plugins/ +PLUGIN_DIR = /qiita_plugins/ # Webserver certificate file paths CERTIFICATE_FILE = @@ -228,38 +228,39 @@ QIIMP = https://localhost:8898/ # # To activate IdP: comment out the following config section -[oidc_localkeycloak] - -# client ID for Qiita as registered at your Identity Provider of choice - CLIENT_ID = qiita - -# client secret to verify Qiita as the correct client. Not all IdPs require -# a client secret! - CLIENT_SECRET = SUPERSECRETSTRING - - -# redirect URL (end point in your Qiita instance), to which the IdP redirects -# after user types in his/her credentials. If you don't want to change code in -# qiita_pet/webserver.py the URL must follow the pattern: -# base_URL/auth/login_OIDC/foo where foo is the name of this config section -# without the oidc_ prefix! - REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak - -# The URL of the well-known json document, specifying how API end points -# like 'authorize', 'token' or 'userinfo' are defined. See e.g. -# https://swagger.io/docs/specification/authentication/ -# openid-connect-discovery/ - WELLKNOWN_URI = http://keycloak:9999/realms/qiita_realm/.well-known/openid-configuration/ - -# a speaking label for the Identity Provider. Section name is used if empty. - LABEL = localkeycloak - -# The scope, i.e. fields about a user, which Qiita requests from the -# Identity Provider, e.g. "profile email eduperson_orcid". -# Will be automatically extended by the scope "openid", to enable the -# "authorize_code" OIDC flow. - SCOPE = openid - -#Optional. Name of a file in qiita_pet/static/img that shall be -#displayed for login through Service Provider, instead of a plain button - LOGO = +#[oidc_localkeycloak] +# +## client ID for Qiita as registered at your Identity Provider of choice +# CLIENT_ID = qiita +# +## client secret to verify Qiita as the correct client. Not all IdPs require +## a client secret! +# CLIENT_SECRET = SUPERSECRETSTRING +# +# +## redirect URL (end point in your Qiita instance), to which the IdP redirects +## after user types in his/her credentials. If you don't want to change code in +## qiita_pet/webserver.py the URL must follow the pattern: +## base_URL/auth/login_OIDC/foo where foo is the name of this config section +## without the oidc_ prefix! +# REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak +# +## The URL of the well-known json document, specifying how API end points +## like 'authorize', 'token' or 'userinfo' are defined. See e.g. +## https://swagger.io/docs/specification/authentication/ +## openid-connect-discovery/ +# WELLKNOWN_URI = http://keycloak:9999/realms/qiita_realm/.well-known/openid-configuration/ +# +## a speaking label for the Identity Provider. Section name is used if empty. +# LABEL = localkeycloak +# +## The scope, i.e. fields about a user, which Qiita requests from the +## Identity Provider, e.g. "profile email eduperson_orcid". +## Will be automatically extended by the scope "openid", to enable the +## "authorize_code" OIDC flow. +# SCOPE = openid +# +##Optional. Name of a file in qiita_pet/static/img that shall be +##displayed for login through Service Provider, instead of a plain button +# LOGO = +# \ No newline at end of file diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile new file mode 100644 index 0000000..f872450 --- /dev/null +++ b/Images/qiita/qiita.dockerfile @@ -0,0 +1,74 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 +ARG MODZIP_VERSION=1.3.0 +ARG NGINX_VERSION=1.26.0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +# install following packages for nginx compilation: libpcre2-dev, libxslt-dev and libgd-dev +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + libpcre2-dev \ + libxslt-dev \ + libgd-dev \ + postgresql-client +RUN apt-get -y install build-essential +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ + conda init + +# create conda env for qiita with all necessary dependencies (conda and pip) +RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy cython anaconda::redis +# TODO: Redis container +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-n", "qiita", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN pip install \ + sphinx \ + sphinx-bootstrap-theme \ + nose-timer \ + Click \ + coverage \ + psycopg2-binary + + +# Clone the Qiita Repo +# RUN git clone -b master https://github.com/qiita-spots/qiita.git +RUN git clone -b auth_oidc https://github.com/jlab/qiita.git + +# We need to install necessary dependencies +# as well as some extra dependencies for psycopg2 to work +RUN git clone https://github.com/psycopg/psycopg2.git +RUN export PATH=/usr/lib/postgresql/14.11/bin/:$PATH +RUN pip install -e psycopg2/. + +# Install pip packaages for Qiita +RUN pip install -e qiita --no-binary redbiom + + +# Copy modified config file to the container +#COPY config_qiita_oidc.cfg /qiita/ +#RUN chmod 755 /qiita/config_qiita_oidc.cfg + +# Copy Bash Script to run Qiita to the container +COPY start_qiita.sh . +RUN chmod 755 start_qiita.sh + +#COPY start_qiita_worker.sh . +#RUN chmod 755 start_qiita_worker.sh + +RUN apt-get install -y curl +# CMD ["conda", "run", "-n", "qiita"] \ No newline at end of file diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 8b79a4d..b1e84d8 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -1,6 +1,16 @@ #!/bin/bash + +CONDA_DIR=/opt/conda +ENV_NAME=qiita +#PORT=21174 + #sleep 300000 -export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" +#export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" + +# We execute qiita-env make every time. We expect that it will fail always but the very first time, as the qiita DB should exist from then on +source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true +# To avoid confusing the user, STDERR is written into a file and only reported if it does not contain the text that we expect to see if it just reports the existing DB +grep 'already present on the system. You can drop it by running' .env-make.err > /dev/null || cat .env-make.err # This was commented out bc it stopped working anymore and i was focusing on fixing something else, if you create the database for the first # time you will have to pick the appropriate options. @@ -11,5 +21,8 @@ export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" # qiita-env make --no-load-ontologies # qiita pet webserver --no-build-docs start --port 21174 --master #fi -#qiita-env make --no-load-ontologies -qiita pet webserver --no-build-docs start --port 21174 --master \ No newline at end of file +#qiita-env make --no-load-ontologies; true +#mkdir -p /qiita/plugins +source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita && qiita pet webserver --no-build-docs start --port $PORT $MASTER + +tail -f /dev/null From b184d6c7337f359dc94dd685ef507eb97c178f58 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:35:46 +0100 Subject: [PATCH 043/287] changed dir and rely on makefile to create empty dirs --- qiita_logs/placeholder.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 qiita_logs/placeholder.txt diff --git a/qiita_logs/placeholder.txt b/qiita_logs/placeholder.txt deleted file mode 100644 index e9f85fa..0000000 --- a/qiita_logs/placeholder.txt +++ /dev/null @@ -1 +0,0 @@ -# placeholder so we can push this folder to git \ No newline at end of file From df95ee743acea19446a487ba47e7f84efbbc251a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:36:17 +0100 Subject: [PATCH 044/287] one log dir for all container --- .gitignore | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 9b8feb7..434458f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ environments/*.env -qiita_logs/*log -qiita_logs/*.pid -nginx_logs/*_log \ No newline at end of file +logs/* +.built_image_* From de749ac8c20a7c45c437f193209d088f09bb8c8e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Feb 2025 14:36:37 +0100 Subject: [PATCH 045/287] restructuring a lot --- compose.yaml | 143 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 57 deletions(-) diff --git a/compose.yaml b/compose.yaml index 859be81..bd7fca7 100644 --- a/compose.yaml +++ b/compose.yaml @@ -12,15 +12,18 @@ services: volumes: - './environments/qiita-db-init.sh:/docker-entrypoint-initdb.d/qiita-db-init.sh' - 'postgres-data:/var/lib/postgresql/data' + - server-plugin-configs:/qiita_plugins networks: - qiita-net + ports: + - "15432:5432" qiita: image: local-qiita:latest build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile - command: ['./start_qiita.sh'] # executes bash script inside the container + command: ['/start_qiita.sh'] # executes bash script inside the container # entrypoint: /bin/bash # stdin_open: true # tty: true @@ -29,28 +32,32 @@ services: # - 127.0.0.1:8383:8383 #damit bur ich dran komme restart: no depends_on: - - qiita-db - - redis + - qiita_worker env_file: - './environments/qiita.env' environment: - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt - - QIITA_CONFIG_FP=/config_qiita_oidc.cfg + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - PORT=21174 + - MASTER=--master volumes: - qiita-data:/qiita - - ./qiita_logs:/qiita_logs - - ./Images/qiita/config_qiita_oidc.cfg:/qiita/config_qiita_oidc.cfg + - ./logs:/logs + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - server-plugin-configs:/qiita_plugins # - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh networks: - qiita-net - # deploy: + ports: + - "21174:21174" + # deploy: # replicas: 3 qiita_worker: image: local-qiita:latest build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile - command: ['./start_qiita_worker.sh'] # executes bash script inside the container + command: ['./start_qiita.sh'] # executes bash script inside the container # entrypoint: /bin/bash # stdin_open: true # tty: true @@ -59,18 +66,20 @@ services: # - 127.0.0.1:8383:8383 #damit bur ich dran komme restart: no depends_on: - - qiita-db - redis - - qiita + - plugin_collector env_file: - './environments/qiita.env' environment: - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt - - QIITA_CONFIG_FP=/config_qiita_oidc.cfg + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - PORT=21175 + - MASTER= volumes: - qiita-data:/qiita - - ./qiita_logs:/qiita_logs - - ./Images/qiita/config_qiita_oidc.cfg:/qiita/config_qiita_oidc.cfg + - ./logs:/logs + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - server-plugin-configs:/qiita_plugins # - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh networks: - qiita-net @@ -87,43 +96,43 @@ services: - ./qiita_logs:/qiita_logs networks: - qiita-net - keycloak: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose - image: quay.io/keycloak/keycloak:24.0.2 - container_name: keycloak - environment: - KC_DB: postgres - KC_DB_URL: jdbc:postgresql://keycloakdb:5432/keycloak - KC_DB_USERNAME: keycloak - KC_DB_PASSWORD: password + #~ keycloak: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose + #~ image: quay.io/keycloak/keycloak:24.0.2 + #~ container_name: keycloak + #~ environment: + #~ KC_DB: postgres + #~ KC_DB_URL: jdbc:postgresql://keycloakdb:5432/keycloak + #~ KC_DB_USERNAME: keycloak + #~ KC_DB_PASSWORD: password - KC_HOSTNAME: keycloak - KC_HOSTNAME_PORT: 9999 - KC_HOSTNAME_STRICT: false - KC_HOSTNAME_STRICT_HTTPS: false + #~ KC_HOSTNAME: keycloak + #~ KC_HOSTNAME_PORT: 9999 + #~ KC_HOSTNAME_STRICT: false + #~ KC_HOSTNAME_STRICT_HTTPS: false - KC_LOG_LEVEL: info - KC_METRICS_ENABLED: false - KC_HEALTH_ENABLED: true - KEYCLOAK_ADMIN: admin - KEYCLOAK_ADMIN_PASSWORD: admin - command: ["start-dev", "--http-port=9999"] - depends_on: - - keycloakdb - ports: - - 127.0.0.1:9999:9999 - networks: - - qiita-net + #~ KC_LOG_LEVEL: info + #~ KC_METRICS_ENABLED: false + #~ KC_HEALTH_ENABLED: true + #~ KEYCLOAK_ADMIN: admin + #~ KEYCLOAK_ADMIN_PASSWORD: admin + #~ command: ["start-dev", "--http-port=9999"] + #~ depends_on: + #~ - keycloakdb + #~ ports: + #~ - 127.0.0.1:9999:9999 + #~ networks: + #~ - qiita-net - keycloakdb: - image: postgres:15 - volumes: - - keycloak-postgres-data:/var/lib/postgresql/data - environment: - POSTGRES_DB: keycloak - POSTGRES_USER: keycloak - POSTGRES_PASSWORD: password - networks: - - qiita-net + #~ keycloakdb: + #~ image: postgres:15 + #~ volumes: + #~ - keycloak-postgres-data:/var/lib/postgresql/data + #~ environment: + #~ POSTGRES_DB: keycloak + #~ POSTGRES_USER: keycloak + #~ POSTGRES_PASSWORD: password + #~ networks: + #~ - qiita-net nginx: image: local-nginx_qiita:latest @@ -140,8 +149,10 @@ services: - qiita volumes: - qiita-data:/qiita - - ./nginx_logs:/qiita_logs - - ./Images/nginx/nginx_qiita.conf:/nginx_qiita.conf + #- ./logs/nginx_access.log:/logs/nginx_access.log + #- ./logs/nginx_error.log:/logs/nginx_error.log + - ./logs:/logs + - ./Images/nginx/nginx_qiita.conf:/qiita_configuration/nginx_qiita.conf networks: - qiita-net @@ -154,24 +165,42 @@ services: restart: no volumes: - qiita-data:/qiita - depends_on: - - qiita - - qiita-db - - qiita_worker + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + #depends_on: + #- qiita + networks: + - qiita-net + + plugin_collector: + image: local-plugin_collector + restart: no networks: - qiita-net + volumes: + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - server-plugin-configs:/qiita_plugins + - qiita-data:/qiita + #- /Daten/Git/jlab/qiita_container_anna/Images/plugin_collector/collect_configs.py:/collect.py + #- /Daten/Git/jlab/qiita_container_anna/Images/plugin_collector/fix_test_db.py:/fix_test_db.py + depends_on: + - qtp-biom # one of the plugins + - qiita-db # as values in qiita DB might be updated + environment: + - QIITA_PLUGINS="qtp-biom:" + command: ['/startup_plugin_collector.sh'] networks: qiita-net: name: qiita-net - external: true + #external: true volumes: postgres-data: name: qiita-postgres-data - keycloak-postgres-data: - name: keycloak-postgres-data + #~ keycloak-postgres-data: + #~ name: keycloak-postgres-data qiita-data: name: qiita-data - + server-plugin-configs: + #server-configurations: \ No newline at end of file From db6108ce09cdc14fb7f2994169822d961791726f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 18 Feb 2025 15:19:43 +0100 Subject: [PATCH 046/287] add trigger server scrup --- Images/qtp-biom/trigger.py | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Images/qtp-biom/trigger.py diff --git a/Images/qtp-biom/trigger.py b/Images/qtp-biom/trigger.py new file mode 100644 index 0000000..07a518c --- /dev/null +++ b/Images/qtp-biom/trigger.py @@ -0,0 +1,60 @@ +import tornado.ioloop +import tornado.web +import json +import subprocess +from glob import glob + +class RunCommandHandler(tornado.web.RequestHandler): + def post(self): + try: + # JSON-Request-Daten lesen + data = json.loads(self.request.body) + qiita_worker_url = data.get('url') + job_id = data.get('job_id') + output_dir = data.get('output_dir') + + #command = data.get("command") + + if not qiita_worker_url or not job_id or not output_dir: + self.set_status(400) + self.write({"error": "Kein Befehl angegeben"}) + return + + # Systembefehl ausfuehren + cmd = 'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-biom; /qtp-biom/scripts/start_biom %s %s %s' % (qiita_worker_url, job_id, output_dir) + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, executable='/bin/bash') + + # Antwort zurueckgeben + self.write({ + "stdout": result.stdout, + "stderr": result.stderr, + "returncode": result.returncode, + "cmd": cmd, + }) + + except Exception as e: + self.set_status(500) + self.write({"error": str(e)}) + +class RunConfigHandler(tornado.web.RequestHandler): + def get(self): + try: + for fp_config in glob('/unshared_plugins/*.conf'): + with open(fp_config, 'r') as f: + self.write('\n'.join(f.readlines()) + '\n') + except Exception as e: + self.set_status(500) + self.write({"error": str(e)}) + +def make_app(): + return tornado.web.Application([ + (r"/run", RunCommandHandler), + (r"/config", RunConfigHandler), + ]) + +if __name__ == "__main__": + app = make_app() + app.listen(5000) # Server auf Port 5000 starten + print("Server laeuft auf http://localhost:5000") + tornado.ioloop.IOLoop.current().start() + From 55152c345b1df79ac59c96febf39299bfbb85b71 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 18 Feb 2025 15:26:05 +0100 Subject: [PATCH 047/287] adding missing files --- Images/nginx/Dockerfile | 83 ------------------- Images/plugin_collector/collect_configs.py | 41 +++++++++ Images/plugin_collector/fix_test_db.py | 54 ++++++++++++ .../plugin_collector.dockerfile | 17 ++++ .../startup_plugin_collector.sh | 12 +++ Images/qiita/Dockerfile | 73 ---------------- Images/qiita/start_qiita_worker.sh | 7 -- Images/qtp-biom/Dockerfile | 51 ------------ Makefile | 58 +++++++++++++ nginx_logs/placeholder.txt | 0 10 files changed, 182 insertions(+), 214 deletions(-) delete mode 100644 Images/nginx/Dockerfile create mode 100644 Images/plugin_collector/collect_configs.py create mode 100644 Images/plugin_collector/fix_test_db.py create mode 100644 Images/plugin_collector/plugin_collector.dockerfile create mode 100644 Images/plugin_collector/startup_plugin_collector.sh delete mode 100644 Images/qiita/Dockerfile delete mode 100755 Images/qiita/start_qiita_worker.sh delete mode 100644 Images/qtp-biom/Dockerfile create mode 100644 Makefile delete mode 100644 nginx_logs/placeholder.txt diff --git a/Images/nginx/Dockerfile b/Images/nginx/Dockerfile deleted file mode 100644 index 2d7b039..0000000 --- a/Images/nginx/Dockerfile +++ /dev/null @@ -1,83 +0,0 @@ -FROM ubuntu:22.04 - -ARG MINIFORGE_VERSION=24.1.2-0 -ARG MODZIP_VERSION=1.3.0 -ARG NGINX_VERSION=1.26.0 - -ENV CONDA_DIR=/opt/conda -ENV PATH=${CONDA_DIR}/bin:${PATH} - -RUN apt-get -y update -RUN apt-get -y install \ - git \ - wget \ - libpcre2-dev \ - libxslt-dev \ - libgd-dev \ - libssl-dev -RUN apt-get -y install build-essential -# install miniforge3 for "conda" -# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile -RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ - /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ - conda init -RUN conda create --quiet --yes -n nginx - -SHELL ["conda", "run", "-n", "nginx", "/bin/bash", "-c"] - -RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz -RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz -RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz -RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz -# fix include for the iconv header -RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c -# ensure runtime library paths are correct and openssl headers can be found at compile time -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ - --http-log-path=var/log/nginx/access.log \ - --error-log-path=var/log/nginx/error.log \ - --pid-path=var/run/nginx/nginx.pid \ - --lock-path=var/run/nginx/nginx.lock \ - --http-client-body-temp-path=var/tmp/nginx/client \ - --http-proxy-temp-path=var/tmp/nginx/proxy \ - --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ - --http-scgi-temp-path=var/tmp/nginx/scgi \ - --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ - --sbin-path=sbin/nginx \ - --conf-path=etc/nginx/nginx.conf \ - --modules-path=lib/nginx/modules \ - --with-threads \ - --with-http_ssl_module \ - --with-http_v2_module \ - --with-http_realip_module \ - --with-http_addition_module \ - --with-http_sub_module \ - --with-http_gunzip_module \ - --with-http_gzip_static_module \ - --with-http_auth_request_module \ - --with-http_secure_link_module \ - --with-http_stub_status_module \ - --with-http_xslt_module=dynamic \ - --with-stream=dynamic \ - --with-http_image_filter_module=dynamic \ - --with-pcre \ - --with-pcre-jit \ - --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ - --with-ld-opt="" \ - --prefix=/usr/local \ - --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ - --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install - -COPY nginx_qiita.conf . -COPY start_nginx.sh . - -RUN chmod 777 nginx_qiita.conf -RUN chmod 777 start_nginx.sh - -RUN mkdir /var/log/nginx - -#ENTRYPOINT ["/bin/bash", "-l", "-c" ] -ENTRYPOINT ["conda", "run", "-n", "nginx", "./start_nginx.sh"] \ No newline at end of file diff --git a/Images/plugin_collector/collect_configs.py b/Images/plugin_collector/collect_configs.py new file mode 100644 index 0000000..24c745b --- /dev/null +++ b/Images/plugin_collector/collect_configs.py @@ -0,0 +1,41 @@ +import os +import requests +import sys + +ENV_PLUGINS = 'QIITA_PLUGINS' +PORT = 5000 +API_ENDPOINT = "config" + +if ENV_PLUGINS not in os.environ or os.environ['QIITA_PLUGINS'] is None or os.environ['QIITA_PLUGINS'] == "": + raise ValueError("No qiita plugins given for which configuration files should be retrieved! Environment variable '%s' not set!" % ENV_PLUGINS) + +var_plugins = os.environ['QIITA_PLUGINS'] +# strip potential quotes +if var_plugins.startswith('"') or var_plugins.startswith("'"): + var_plugins = var_plugins[1:] +if var_plugins.endswith('"') or var_plugins.endswith("'"): + var_plugins = var_plugins[:-1] + +containers = [c for c in var_plugins.split(':') if c != ""] + +print("retrieving %i qiita plugin configurations:" % len(containers), file=sys.stderr) +for i, container in enumerate(containers): + if container == "": + continue + print(' (%i/%i) %s' % (i+1, len(containers), container), end="", file=sys.stderr) + url = 'http://qiita-container-anna-%s-1:%s/%s' % (container, PORT, API_ENDPOINT) + print(" '%s'" % url, end="", file=sys.stderr) + + req = requests.get(url) + if req.status_code != 200: + print(" failed.", file=sys.stderr) + else: + fp_config = '/qiita_plugins/%s.conf' % container + if os.path.exists(fp_config): + print(" already present.", file=sys.stderr) + else: + with open(fp_config, 'w') as f: + f.write(req.content.decode('utf-8')) + print(" ok.", file=sys.stderr) + +print("done.", file=sys.stderr) diff --git a/Images/plugin_collector/fix_test_db.py b/Images/plugin_collector/fix_test_db.py new file mode 100644 index 0000000..15ae4ef --- /dev/null +++ b/Images/plugin_collector/fix_test_db.py @@ -0,0 +1,54 @@ +import os +from glob import glob +import configparser +import psycopg2 + + +qiita_config = configparser.ConfigParser() +qiita_config.read('/qiita_configurations/qiita_server.cfg') +is_test = qiita_config['main']['TEST_ENVIRONMENT'].upper() == 'TRUE' +print("qiita is in %s mode." % ('TEST' if is_test else 'PRODUCTIVE')) + +if is_test: + conn = psycopg2.connect(database=qiita_config['postgres']['DATABASE'], + host=qiita_config['postgres']['HOST'], + user=qiita_config['postgres']['ADMIN_USER'], + password=qiita_config['postgres']['ADMIN_PASSWORD'], + port=qiita_config['postgres']['PORT']) + cursor = conn.cursor() + + fps_plugin_configs = glob('/qiita_plugins/*.conf') + print("Updating plugin credentials in dummy test DB with actual values from %i plugins." % len(fps_plugin_configs)) + for i, fp_plugin_config in enumerate(fps_plugin_configs): + config = configparser.ConfigParser() + config.read(fp_plugin_config) + + print(" (%i/%i) %s: " % (i+1, len(fps_plugin_configs), config['main']['name']), end="") + + SQL_get_softwareID_clientID = "SELECT software.software_id, oauth_software.client_id FROM qiita.software JOIN qiita.oauth_software ON qiita.software.software_id=qiita.oauth_software.software_id WHERE name='%s' AND version='%s';" % ( + config['main']['name'], config['main']['version'] + ) + cursor.execute(SQL_get_softwareID_clientID) + old_software_id, old_client_id = cursor.fetchone() + + if config['oauth2']['client_id'] != old_client_id: + SQL_update = "BEGIN; " + # add in the new client secret + SQL_update += "INSERT INTO qiita.oauth_identifiers VALUES ('%s', '%s');" % (config['oauth2']['client_id'], config['oauth2']['client_secret']) + # add in a new software_id to client_id row + SQL_update += "INSERT INTO qiita.oauth_software VALUES (%s, '%s');" % (old_software_id, config['oauth2']['client_id']) + # remove old client_id + SQL_update += "DELETE FROM qiita.oauth_software WHERE software_id=%s AND client_id='%s';" % (old_software_id, old_client_id) + # delete old client_id client_secret relation + SQL_update += "DELETE FROM qiita.oauth_identifiers WHERE client_id='%s';" % old_client_id + # replace ENVIRONMENT_SCRIPT with the one given in config file + SQL_update += "UPDATE qiita.software SET environment_script='%s' WHERE software_id='%s';" % (config['main']['ENVIRONMENT_SCRIPT'], old_software_id) + # replace START_SCRIPT with the one given in config file + SQL_update += "UPDATE qiita.software SET start_script='%s' WHERE software_id='%s';" % (config['main']['START_SCRIPT'], old_software_id) + SQL_update += " COMMIT;" + cursor.execute(SQL_update) + print(" credentials replaced.") + else: + print(" credentials already up to date.") + + conn.close() diff --git a/Images/plugin_collector/plugin_collector.dockerfile b/Images/plugin_collector/plugin_collector.dockerfile new file mode 100644 index 0000000..5bdf0b2 --- /dev/null +++ b/Images/plugin_collector/plugin_collector.dockerfile @@ -0,0 +1,17 @@ +FROM ubuntu:24.04 + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + curl \ + python3 \ + python3-requests \ + python3-psycopg2 + +COPY collect_configs.py /collect_configs.py +COPY fix_test_db.py /fix_test_db.py +COPY startup_plugin_collector.sh /startup_plugin_collector.sh +RUN chmod u+x /startup_plugin_collector.sh + +COPY Certificates /unshared_certificates + +CMD /startup_plugin_collector.sh \ No newline at end of file diff --git a/Images/plugin_collector/startup_plugin_collector.sh b/Images/plugin_collector/startup_plugin_collector.sh new file mode 100644 index 0000000..6dd2ad1 --- /dev/null +++ b/Images/plugin_collector/startup_plugin_collector.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# copy certificates into shared volume, if not present there already +for f in `find /unshared_certificates -type f -name "*" | xargs`; do + test -f /qiita_certificates/`basename $f` || cp -v $f /qiita_certificates/`basename $f`; +done + +# it seems to be necessary to give the plugin container some lead time +# TODO: this might be more appropriately be addressed with healthchecks in the compose file +sleep 3 +python3 /collect_configs.py +python3 /fix_test_db.py diff --git a/Images/qiita/Dockerfile b/Images/qiita/Dockerfile deleted file mode 100644 index 9359ba5..0000000 --- a/Images/qiita/Dockerfile +++ /dev/null @@ -1,73 +0,0 @@ -FROM ubuntu:24.04 - -ARG MINIFORGE_VERSION=24.1.2-0 -ARG MODZIP_VERSION=1.3.0 -ARG NGINX_VERSION=1.26.0 - -ENV CONDA_DIR=/opt/conda -ENV PATH=${CONDA_DIR}/bin:${PATH} - -RUN apt-get -y update -# install following packages for nginx compilation: libpcre2-dev, libxslt-dev and libgd-dev -RUN apt-get -y --fix-missing install \ - git \ - wget \ - libpq-dev \ - python3-dev \ - gcc \ - libpcre2-dev \ - libxslt-dev \ - libgd-dev \ - postgresql-client -RUN apt-get -y install build-essential -# install miniforge3 for "conda" -# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile -RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ - /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ - conda init - -# create conda env for qiita with all necessary dependencies (conda and pip) -RUN conda create --quiet --yes -n qiita python=3.9 pip libgfortran numpy cython anaconda::redis -# TODO: Redis container -# Make RUN commands use the new environment: -# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 -SHELL ["conda", "run", "-n", "qiita", "/bin/bash", "-c"] - -RUN pip install -U pip -RUN pip install \ - sphinx \ - sphinx-bootstrap-theme \ - nose-timer \ - Click \ - coverage \ - psycopg2-binary - - -# Clone the Qiita Repo -# RUN git clone -b master https://github.com/qiita-spots/qiita.git -RUN git clone -b auth_oidc https://github.com/jlab/qiita.git - -# We need to install necessary dependencies -# as well as some extra dependencies for psycopg2 to work -RUN git clone https://github.com/psycopg/psycopg2.git -RUN export PATH=/usr/lib/postgresql/14.11/bin/:$PATH -RUN pip install -e psycopg2/. - -# Install pip packaages for Qiita -RUN pip install -e qiita --no-binary redbiom - - -# Copy modified config file to the container - COPY config_qiita_oidc.cfg /qiita/ - RUN chmod 755 /qiita/config_qiita_oidc.cfg - -# Copy Bash Script to run Qiita to the container - COPY start_qiita.sh . - RUN chmod 755 start_qiita.sh - - COPY start_qiita_worker.sh . - RUN chmod 755 start_qiita_worker.sh - -ENTRYPOINT ["conda", "run", "-n", "qiita"] \ No newline at end of file diff --git a/Images/qiita/start_qiita_worker.sh b/Images/qiita/start_qiita_worker.sh deleted file mode 100755 index 8316b9c..0000000 --- a/Images/qiita/start_qiita_worker.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - - -export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" - -qiita pet webserver --no-build-docs start --port 21175 - diff --git a/Images/qtp-biom/Dockerfile b/Images/qtp-biom/Dockerfile deleted file mode 100644 index c5c059c..0000000 --- a/Images/qtp-biom/Dockerfile +++ /dev/null @@ -1,51 +0,0 @@ -FROM ubuntu:24.04 - -ARG MINIFORGE_VERSION=24.1.2-0 - -ENV CONDA_DIR=/opt/conda -ENV PATH=${CONDA_DIR}/bin:${PATH} - -RUN apt-get -y update -RUN apt-get -y --fix-missing install \ - git \ - wget \ - libpq-dev \ - python3-dev \ - gcc -RUN apt-get -y install build-essential -# install miniforge3 for "conda" -# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile -RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ - /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ - conda init - -# Download qtp-biom yaml -RUN wget https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml - -# Create conda env -RUN conda env create --quiet -n qtp-biom --file qiime2-2022.11-py38-linux-conda.yml - -# Export cert and config filepaths -RUN export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg - -# Make RUN commands use the new environment: -# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 -SHELL ["conda", "run", "-n", "qtp-biom", "/bin/bash", "-c"] - -RUN pip install -U pip -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN pip install https://github.com/qiita-spots/qtp-biom/archive/master.zip -RUN git clone https://github.com/qiita-spots/qtp-biom.git - -RUN pip install --upgrade certifi -RUN pip install pip-system-certs - -RUN sed -i 's/2.1.4 - Qiime2/2.1.5 - Qiime2 Annas Version/g' /qtp-biom/qtp_biom/__init__.py - -COPY start_qtp-biom.sh . -RUN chmod 755 start_qtp-biom.sh - -ENTRYPOINT ["conda", "run", "-n", "qtp-biom", "./start_qtp-biom.sh"] \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f9c409a --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +PODMAN_FLAGS = +PODMAN_BIN = docker buildx +CERTNAME=stefan +OPENSSL=/bin/openssl + +Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/stefan_cert.conf + # === create own certificates === + mkdir -p Certificates/ + # Generate a new root CA private key and certificate + cd $@/ && $(OPENSSL) req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=qiita-container-anna-qiita-1/C=DE/L=Giessen" -keyout $(CERTNAME)_rootca.key -out $(CERTNAME)_rootca.crt + # Generate a new server private key + cd $@/ && $(OPENSSL) genrsa -out $(CERTNAME)_server.key 2048 + # Copy the following to a new file named csr.conf and modify to suit your needs + # Copy the following to a new file named cert.conf and modify to suit your needs + # Nils: alt_names is the important aspect. Make entries for all valid hostnames with which services shall be addressed + cp $^ $@/ + # Generate a certificate signing request + cd $@/ && $(OPENSSL) req -new -key $(CERTNAME)_server.key -out $(CERTNAME)_server.csr -config $(CERTNAME)_csr.conf + # Generate a new signed server.crt to use with your server.key + cd $@/ && $(OPENSSL) x509 -req -in $(CERTNAME)_server.csr -CA $(CERTNAME)_rootca.crt -CAkey $(CERTNAME)_rootca.key -CAcreateserial -out $(CERTNAME)_server.crt -days 365 -sha256 -extfile $(CERTNAME)_cert.conf + # === end: create own certificates === + +.built_image_biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh Images/qtp-biom/trigger.py Certificates/ + rm -rf Images/qtp-biom/Certificates && cp -r Certificates Images/qtp-biom/ + cd Images/qtp-biom && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qtp-biom + touch .built_image_biom + +.built_image_nginx: Images/nginx/nginx.dockerfile Images/nginx/start_nginx.sh Images/nginx/nginx_qiita.conf + cd Images/nginx && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-nginx_qiita + mkdir -p ./logs + touch ./logs/nginx_access.log ./logs/nginx_error.log + chmod a+rw ./logs/nginx_access.log ./logs/nginx_error.log + touch .built_image_nginx + +.built_image_qiita: Images/qiita/qiita.dockerfile Images/qiita/config_qiita_oidc.cfg Images/qiita/start_qiita.sh Images/qiita/supervisor_foreground.conf Images/qiita/start_plugin.py + test -d src/qiita || git clone -b auth_oidc https://github.com/jlab/qiita.git src/qiita + # remove configuration and certificate files from upstream qiita repo + rm -rf src/qiita/qiita_core/support_files + cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita + touch .built_image_qiita + +.built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh Certificates/ + cp -r Certificates/ Images/plugin_collector/ + cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector + touch .built_image_plugin_collector + +images: .built_image_biom .built_image_nginx .built_image_qiita .built_image_plugin_collector + +environments/qiita_db.env: environments/qiita_db.env.example + cp environments/qiita_db.env.example environments/qiita_db.env + sed -E -i "s/^POSTGRES_PASSWORD=.+$$/POSTGRES_PASSWORD=postgres/" environments/qiita_db.env + +environments/qiita.env: environments/qiita.env.example + cp environments/qiita.env.example environments/qiita.env + +config: environments/qiita_db.env environments/qiita.env + +all: config images \ No newline at end of file diff --git a/nginx_logs/placeholder.txt b/nginx_logs/placeholder.txt deleted file mode 100644 index e69de29..0000000 From 14f0d62e5dba88176ec5bdac77bb4cb174784841 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 18 Feb 2025 15:44:04 +0100 Subject: [PATCH 048/287] conf files for cas --- Images/plugin_collector/stefan_cert.conf | 12 +++++++++++ Images/plugin_collector/stefan_csr.conf | 26 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 Images/plugin_collector/stefan_cert.conf create mode 100644 Images/plugin_collector/stefan_csr.conf diff --git a/Images/plugin_collector/stefan_cert.conf b/Images/plugin_collector/stefan_cert.conf new file mode 100644 index 0000000..9479793 --- /dev/null +++ b/Images/plugin_collector/stefan_cert.conf @@ -0,0 +1,12 @@ +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = localhost +DNS.2 = qiita-container-anna-qiita-1 +DNS.3 = qiita-container-anna-qiita-worker-1 +DNS.4 = qiita-container-anna-qiita-worker-2 +DNS.5 = qiita-container-anna-qiita-worker-3 +DNS.6 = qiita-container-anna-nginx-1 \ No newline at end of file diff --git a/Images/plugin_collector/stefan_csr.conf b/Images/plugin_collector/stefan_csr.conf new file mode 100644 index 0000000..2f42bb4 --- /dev/null +++ b/Images/plugin_collector/stefan_csr.conf @@ -0,0 +1,26 @@ +[ req ] +default_bits = 2048 +prompt = no +default_md = sha256 +req_extensions = req_ext +distinguished_name = dn + +[ dn ] +C = DE +ST = Hesse +L = Giessen +O = JLU +OU = Stefan Janssen +CN = localhost + +[ req_ext ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = localhost +IP.1 = 127.0.0.1 +DNS.2 = qiita-container-anna-qiita-1 +DNS.3 = qiita-container-anna-qiita-worker-1 +DNS.4 = qiita-container-anna-qiita-worker-2 +DNS.5 = qiita-container-anna-qiita-worker-3 +DNS.6 = qiita-container-anna-nginx-1 \ No newline at end of file From 398bfb763b820f06b29271d5777d695e81d1d454 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:26:24 +0100 Subject: [PATCH 049/287] qiita worker replicas all listen on the same port + own certificates instead of qiita shipped ones --- Images/nginx/nginx_qiita.conf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf index 537cd54..cf8ba9d 100644 --- a/Images/nginx/nginx_qiita.conf +++ b/Images/nginx/nginx_qiita.conf @@ -13,9 +13,9 @@ http { # ports to redirect for mainqiita upstream mainqiita { server qiita:21174; - server qiita_container_anna-qiita_worker-2:21175; - server qiita_container_anna-qiita_worker-2:21175; - server qiita_container_anna-qiita_worker-2:21175; + server qiita-container-anna-qiita-worker-1:21175; + server qiita-container-anna-qiita-worker-2:21175; + server qiita-container-anna-qiita-worker-3:21175; } # define variables for the actions that shall be taken for websocket handshake @@ -38,8 +38,8 @@ http { access_log /logs/nginx_access.log; - ssl_certificate /qiita/qiita_core/support_files/ci_server.crt; - ssl_certificate_key /qiita/qiita_core/support_files/ci_server.key; + ssl_certificate /qiita_certificates/stefan_server.crt; + ssl_certificate_key /qiita_certificates/stefan_server.key; ssl_session_timeout 5m; From 45049b7551cc96dffa56932e0c3d15735733645e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:26:59 +0100 Subject: [PATCH 050/287] set certificat paths through qiita config file --- Images/qiita/config_qiita_oidc.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index dd596d3..b623054 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -54,8 +54,8 @@ PLUGIN_LAUNCHER = qiita-plugin-launcher PLUGIN_DIR = /qiita_plugins/ # Webserver certificate file paths -CERTIFICATE_FILE = -KEY_FILE = +CERTIFICATE_FILE = /qiita_certificates/stefan_server.crt +KEY_FILE = /qiita_certificates/stefan_server.key # The value used to secure cookies used for user sessions. A suitable value can # be generated with: From 4de8a24f2a79f323b63884c23c56681562ae5822 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:27:30 +0100 Subject: [PATCH 051/287] add startup script for plugin --- Images/qiita/qiita.dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index f872450..ffbe0ed 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -71,4 +71,10 @@ RUN chmod 755 start_qiita.sh #RUN chmod 755 start_qiita_worker.sh RUN apt-get install -y curl +COPY start_plugin.py /start_plugin.py +RUN chmod a+x /start_plugin.py + +# hide certificate and server configuration copy from source code +RUN rm -rf /qiita/qiita_core/support_files + # CMD ["conda", "run", "-n", "qiita"] \ No newline at end of file From 5629f864e8012f99f0098f40084b03518cfca843 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:28:04 +0100 Subject: [PATCH 052/287] more logging --- Images/qiita/start_qiita.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index b1e84d8..2a65826 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -6,6 +6,9 @@ ENV_NAME=qiita #sleep 300000 #export QIITA_CONFIG_FP="/qiita/config_qiita_oidc.cfg" +if [ -n "${MASTER}" ] && [ ! -d /qiita/qiita_db/__pycache__ ]; then + source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; pip install -e . --no-binary redbiom; +fi # We execute qiita-env make every time. We expect that it will fail always but the very first time, as the qiita DB should exist from then on source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true @@ -23,6 +26,7 @@ grep 'already present on the system. You can drop it by running' .env-make.err > #fi #qiita-env make --no-load-ontologies; true #mkdir -p /qiita/plugins -source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita && qiita pet webserver --no-build-docs start --port $PORT $MASTER +#sleep 3 +source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita && qiita pet webserver --no-build-docs start --port $PORT $MASTER 2> /logs/qiita_pet$MASTER.log 1>&2 tail -f /dev/null From a90ae9c9dc2a3c3ae005a0cd091eaae0249bbd42 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:28:33 +0100 Subject: [PATCH 053/287] desperate ideas for certificats --- Images/qtp-biom/qtp-biom.dockerfile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index a4715b3..042a448 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -43,8 +43,6 @@ RUN pip install pip-system-certs RUN conda install tornado COPY trigger.py /trigger.py -## Export cert and config filepaths -RUN export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg WORKDIR / @@ -55,7 +53,10 @@ RUN chmod 755 start_qtp-biom.sh RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ -RUN /qtp-biom/scripts/configure_biom --env-script "source /home/joe/.bashrc; conda activate env_deblur" --server-cert /qiita/qiita_core/support_files/ci_rootca.crt - +## Export cert and config filepaths +COPY Certificates /unshared_certificates +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert /unshared_certificates/ci_rootca.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf -CMD ["conda", "run", "-n", "qtp-biom", "./start_qtp-biom.sh"] \ No newline at end of file +CMD ["conda", "run", "-n", "qtp-biom", "./start_qtp-biom.sh"] From 34892f18a73e531a69d77e6c98dc8ac1fd1f88c2 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:29:03 +0100 Subject: [PATCH 054/287] don't use env for cert filepath --- Images/qtp-biom/start_qtp-biom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index 085cfdd..4d07824 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -1,6 +1,6 @@ #!/bin/bash -export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg CONDA_DIR=/opt/conda ENV_NAME=qtp-biom From 622edaa03bb0ef3279e75bdd123880c1de392a7c Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:30:01 +0100 Subject: [PATCH 055/287] avoid using _ in service names --- compose.yaml | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/compose.yaml b/compose.yaml index bd7fca7..61a18a8 100644 --- a/compose.yaml +++ b/compose.yaml @@ -32,19 +32,21 @@ services: # - 127.0.0.1:8383:8383 #damit bur ich dran komme restart: no depends_on: - - qiita_worker + - qiita-worker env_file: - './environments/qiita.env' environment: - - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt + #- QIITA_ROOTCA_CERT=/qiita_certificates/stefan_rootca.crt # does not seem to have effect if not set in config file - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg - PORT=21174 - MASTER=--master volumes: - - qiita-data:/qiita + #- qiita-data:/qiita + - ./src/qiita:/qiita:U - ./logs:/logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - server-plugin-configs:/qiita_plugins + - server-certificates:/qiita_certificates # - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh networks: - qiita-net @@ -52,7 +54,7 @@ services: - "21174:21174" # deploy: # replicas: 3 - qiita_worker: + qiita-worker: image: local-qiita:latest build: # image wird hier direkt gebaut context: ./Images/qiita @@ -67,11 +69,11 @@ services: restart: no depends_on: - redis - - plugin_collector + - plugin-collector env_file: - './environments/qiita.env' environment: - - QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_rootca.crt + #- QIITA_ROOTCA_CERT=/qiita_certificates/stefan_rootca.crt # does not seem to have effect if not set in config file - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg - PORT=21175 - MASTER= @@ -80,6 +82,7 @@ services: - ./logs:/logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - server-plugin-configs:/qiita_plugins + - server-certificates:/qiita_certificates # - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh networks: - qiita-net @@ -153,6 +156,7 @@ services: #- ./logs/nginx_error.log:/logs/nginx_error.log - ./logs:/logs - ./Images/nginx/nginx_qiita.conf:/qiita_configuration/nginx_qiita.conf + - server-certificates:/qiita_certificates networks: - qiita-net @@ -165,13 +169,15 @@ services: restart: no volumes: - qiita-data:/qiita - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? #depends_on: #- qiita networks: - qiita-net - plugin_collector: + plugin-collector: + # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers + # to compile all q*.conf files from plugin containers in the server-plugin-configs volume image: local-plugin_collector restart: no networks: @@ -180,8 +186,9 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - server-plugin-configs:/qiita_plugins - qiita-data:/qiita - #- /Daten/Git/jlab/qiita_container_anna/Images/plugin_collector/collect_configs.py:/collect.py - #- /Daten/Git/jlab/qiita_container_anna/Images/plugin_collector/fix_test_db.py:/fix_test_db.py + - server-certificates:/qiita_certificates + #- /Daten/Git/jlab/qiita-container-anna/Images/plugin_collector/collect_configs.py:/collect.py + #- /Daten/Git/jlab/qiita-container-anna/Images/plugin_collector/fix_test_db.py:/fix_test_db.py depends_on: - qtp-biom # one of the plugins - qiita-db # as values in qiita DB might be updated @@ -202,5 +209,5 @@ volumes: #~ name: keycloak-postgres-data qiita-data: name: qiita-data - server-plugin-configs: - #server-configurations: \ No newline at end of file + server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files + server-certificates: # server one copy of qiita server (master and workers) certificate files. If not in volume, "plugin_collector" should copy them there \ No newline at end of file From c02177942352274bf5f29c78eed323ca9727e49c Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 4 Mar 2025 08:30:55 +0100 Subject: [PATCH 056/287] add startup script --- Images/qiita/start_plugin.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Images/qiita/start_plugin.py diff --git a/Images/qiita/start_plugin.py b/Images/qiita/start_plugin.py new file mode 100644 index 0000000..5afde47 --- /dev/null +++ b/Images/qiita/start_plugin.py @@ -0,0 +1,19 @@ +import os +import sys +import requests +import json + +PORT = 5000 +API_ENDPOINT = "run" + +pluginname, qiita_server_url, job_id, output_dir = sys.argv[1:] + +req = requests.post('http://qiita-container-anna-%s-1:%s/run' % (pluginname, PORT), + json={'url': qiita_server_url, + 'job_id': job_id, + 'output_dir': output_dir}) +print(req.status_code) + +retvalues = json.loads(req.text) +print("=== request STDERR ===\n%s" % retvalues['stderr']) +print("=== request STDOUT ===\n%s" % retvalues['stdout']) From 70dbc531366c22b1d2df2609f31131ece7596c33 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 08:30:27 +0100 Subject: [PATCH 057/287] adding some comments --- Images/qiita/qiita.dockerfile | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index ffbe0ed..18a4d32 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -43,7 +43,7 @@ RUN pip install \ Click \ coverage \ psycopg2-binary - + # Clone the Qiita Repo # RUN git clone -b master https://github.com/qiita-spots/qiita.git @@ -58,18 +58,12 @@ RUN pip install -e psycopg2/. # Install pip packaages for Qiita RUN pip install -e qiita --no-binary redbiom +# A qiita configuration file is directly mounted into the qiita container via the compose file -# Copy modified config file to the container -#COPY config_qiita_oidc.cfg /qiita/ -#RUN chmod 755 /qiita/config_qiita_oidc.cfg - -# Copy Bash Script to run Qiita to the container +# Copy Bash Script to run Qiita to the container. start_qiita differentiates between one "master" and multiple workers COPY start_qiita.sh . RUN chmod 755 start_qiita.sh -#COPY start_qiita_worker.sh . -#RUN chmod 755 start_qiita_worker.sh - RUN apt-get install -y curl COPY start_plugin.py /start_plugin.py RUN chmod a+x /start_plugin.py @@ -77,4 +71,4 @@ RUN chmod a+x /start_plugin.py # hide certificate and server configuration copy from source code RUN rm -rf /qiita/qiita_core/support_files -# CMD ["conda", "run", "-n", "qiita"] \ No newline at end of file +# CMD ["conda", "run", "-n", "qiita"] From 05fd6e48d7dce3d8335778b4d4e6f32006e80444 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 08:30:44 +0100 Subject: [PATCH 058/287] export the SSL affecting env variables --- Images/qtp-biom/qtp-biom.dockerfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 042a448..deac39f 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -43,6 +43,7 @@ RUN pip install pip-system-certs RUN conda install tornado COPY trigger.py /trigger.py +# TODO: should the plugin get the server configuration?! RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg WORKDIR / @@ -55,8 +56,12 @@ ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert /unshared_certificates/ci_rootca.crt +RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert /unshared_certificates/stefan_server.crt RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf CMD ["conda", "run", "-n", "qtp-biom", "./start_qtp-biom.sh"] From a95b76aa4389983304081d2584417f20ede13016 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 08:31:12 +0100 Subject: [PATCH 059/287] more verbose debugging in qiita --- compose.yaml | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/compose.yaml b/compose.yaml index 61a18a8..9dcecad 100644 --- a/compose.yaml +++ b/compose.yaml @@ -19,7 +19,7 @@ services: - "15432:5432" qiita: - image: local-qiita:latest + image: local-qiita:latest build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -40,6 +40,7 @@ services: - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg - PORT=21174 - MASTER=--master + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG volumes: #- qiita-data:/qiita - ./src/qiita:/qiita:U @@ -55,7 +56,7 @@ services: # deploy: # replicas: 3 qiita-worker: - image: local-qiita:latest + image: local-qiita:latest build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -77,6 +78,7 @@ services: - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg - PORT=21175 - MASTER= + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG volumes: - qiita-data:/qiita - ./logs:/logs @@ -94,9 +96,9 @@ services: command: > sh -c "redis-server --port 7777 && redis-server --port 6379" - volumes: + volumes: - qiita-data:/qiita - - ./qiita_logs:/qiita_logs + - ./logs:/logs networks: - qiita-net #~ keycloak: # from https://stackoverflow.com/questions/78071458/keycloak-docker-compose @@ -136,7 +138,7 @@ services: #~ POSTGRES_PASSWORD: password #~ networks: #~ - qiita-net - + nginx: image: local-nginx_qiita:latest build: @@ -159,7 +161,7 @@ services: - server-certificates:/qiita_certificates networks: - qiita-net - + qtp-biom: image: local-qtp-biom:latest command: ['./start_qtp-biom.sh'] @@ -170,11 +172,16 @@ services: volumes: - qiita-data:/qiita - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG #depends_on: #- qiita networks: - qiita-net - + plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -201,7 +208,7 @@ networks: name: qiita-net #external: true - + volumes: postgres-data: name: qiita-postgres-data @@ -210,4 +217,4 @@ volumes: qiita-data: name: qiita-data server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files - server-certificates: # server one copy of qiita server (master and workers) certificate files. If not in volume, "plugin_collector" should copy them there \ No newline at end of file + server-certificates: # server one copy of qiita server (master and workers) certificate files. If not in volume, "plugin_collector" should copy them there From cf55ba6dbba90fc17a9a614baa9ad827793cfb03 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 08:43:06 +0100 Subject: [PATCH 060/287] use service name --- Images/qiita/config_qiita_oidc.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index b623054..68ddda5 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -23,7 +23,7 @@ LOG_DIR = /logs/ REQUIRE_APPROVAL = True # Base URL: DO NOT ADD TRAILING SLASH -BASE_URL = https://localhost:8383 +BASE_URL = https://qiita-container-anna-nginx-1:8383 # Download path files UPLOAD_DATA_DIR = /qiita/qiita_db/support_files/test_data/uploads/ @@ -263,4 +263,4 @@ QIIMP = https://localhost:8898/ ##Optional. Name of a file in qiita_pet/static/img that shall be ##displayed for login through Service Provider, instead of a plain button # LOGO = -# \ No newline at end of file +# From cecd0528685fa74102f20ea60d21f5b4d1a3c52c Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 12:57:06 +0100 Subject: [PATCH 061/287] start with parameters to specialize to different plugins --- Images/qtp-biom/trigger.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Images/qtp-biom/trigger.py b/Images/qtp-biom/trigger.py index 07a518c..20c2957 100644 --- a/Images/qtp-biom/trigger.py +++ b/Images/qtp-biom/trigger.py @@ -3,6 +3,11 @@ import json import subprocess from glob import glob +import sys + +conda_env_name = None +plugin_start_script = None +plugin_src_dir = None class RunCommandHandler(tornado.web.RequestHandler): def post(self): @@ -12,7 +17,7 @@ def post(self): qiita_worker_url = data.get('url') job_id = data.get('job_id') output_dir = data.get('output_dir') - + #command = data.get("command") if not qiita_worker_url or not job_id or not output_dir: @@ -21,7 +26,7 @@ def post(self): return # Systembefehl ausfuehren - cmd = 'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-biom; /qtp-biom/scripts/start_biom %s %s %s' % (qiita_worker_url, job_id, output_dir) + cmd = 'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s; %s/scripts/%s %s %s %s' % (conda_env_name, plugin_src_dir, plugin_start_script, qiita_worker_url, job_id, output_dir) result = subprocess.run(cmd, shell=True, capture_output=True, text=True, executable='/bin/bash') # Antwort zurueckgeben @@ -53,8 +58,11 @@ def make_app(): ]) if __name__ == "__main__": + conda_env_name = sys.argv[1] + plugin_start_script = sys.argv[2] + plugin_src_dir = sys.argv[3] + app = make_app() app.listen(5000) # Server auf Port 5000 starten print("Server laeuft auf http://localhost:5000") tornado.ioloop.IOLoop.current().start() - From a73febafa20056b5fcb16d2657447b6a3b135334 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 12:57:31 +0100 Subject: [PATCH 062/287] provide plugin specific parameters --- Images/qtp-biom/start_qtp-biom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index 4d07824..912c38d 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -12,6 +12,6 @@ ENV_NAME=qtp-biom #start_biom https://localhost:8383 register ignored #start_biom http://qiita:8383 register ignored #source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py -source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-biom; cd / && python trigger.py +source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-biom; cd / && python trigger.py qtp-biom start_biom /qtp-biom tail -f /dev/null From ed2dcd4e391468c797e0d8d644d51ea0bf6f5015 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 12:58:03 +0100 Subject: [PATCH 063/287] adding qtp-sequencing --- .../qtp-sequencing/qtp-sequencing.dockerfile | 64 +++++++++++++++++++ Images/qtp-sequencing/start_qtp-sequencing.sh | 17 +++++ Makefile | 16 +++-- compose.yaml | 23 ++++++- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 Images/qtp-sequencing/qtp-sequencing.dockerfile create mode 100644 Images/qtp-sequencing/start_qtp-sequencing.sh diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile new file mode 100644 index 0000000..2635b6a --- /dev/null +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -0,0 +1,64 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# Create conda env +RUN conda create --name qtp-sequencing -y -c conda-forge -c bioconda pip pigz quast fqtools python=3.9 +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-sequencing", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone https://github.com/qiita-spots/qtp-sequencing.git +WORKDIR qtp-sequencing +RUN pip install -e . +RUN pip install --upgrade certifi +RUN pip install pip-system-certs +RUN conda install tornado +COPY trigger.py /trigger.py + +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qtp-sequencing.sh . +RUN chmod 755 start_qtp-sequencing.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN /qtp-sequencing/scripts/configure_qtp_sequencing --env-script "true" --ca-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-sequencing/" /unshared_plugins/*.conf + +CMD ["conda", "run", "-n", "qtp-sequencing", "./start_qtp-sequencing.sh"] diff --git a/Images/qtp-sequencing/start_qtp-sequencing.sh b/Images/qtp-sequencing/start_qtp-sequencing.sh new file mode 100644 index 0000000..d3fbf11 --- /dev/null +++ b/Images/qtp-sequencing/start_qtp-sequencing.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qtp-sequencing + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-sequencing; cd / && python trigger.py qtp-sequencing start_qtp_sequencing /qtp-sequencing + +tail -f /dev/null diff --git a/Makefile b/Makefile index f9c409a..c30faa2 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PODMAN_FLAGS = +PODMAN_FLAGS = PODMAN_BIN = docker buildx CERTNAME=stefan OPENSSL=/bin/openssl @@ -25,6 +25,12 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s cd Images/qtp-biom && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qtp-biom touch .built_image_biom +.built_image_sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh Images/qtp-biom/trigger.py Certificates/ + rm -rf Images/qtp-sequencing/Certificates && cp -r Certificates Images/qtp-sequencing/ + cp Images/qtp-biom/trigger.py Images/qtp-sequencing/ + cd Images/qtp-sequencing && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qtp-sequencing + touch .built_image_sequencing + .built_image_nginx: Images/nginx/nginx.dockerfile Images/nginx/start_nginx.sh Images/nginx/nginx_qiita.conf cd Images/nginx && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-nginx_qiita mkdir -p ./logs @@ -44,15 +50,15 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_biom .built_image_nginx .built_image_qiita .built_image_plugin_collector +images: .built_image_biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_sequencing environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env sed -E -i "s/^POSTGRES_PASSWORD=.+$$/POSTGRES_PASSWORD=postgres/" environments/qiita_db.env - + environments/qiita.env: environments/qiita.env.example cp environments/qiita.env.example environments/qiita.env - + config: environments/qiita_db.env environments/qiita.env -all: config images \ No newline at end of file +all: config images diff --git a/compose.yaml b/compose.yaml index 9dcecad..f6ed81e 100644 --- a/compose.yaml +++ b/compose.yaml @@ -182,6 +182,26 @@ services: networks: - qiita-net + qtp-sequencing: + image: local-qtp-sequencing:latest + command: ['./start_qtp-sequencing.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -198,9 +218,10 @@ services: #- /Daten/Git/jlab/qiita-container-anna/Images/plugin_collector/fix_test_db.py:/fix_test_db.py depends_on: - qtp-biom # one of the plugins + - qtp-sequencing - qiita-db # as values in qiita DB might be updated environment: - - QIITA_PLUGINS="qtp-biom:" + - QIITA_PLUGINS="qtp-biom:qtp-sequencing:" command: ['/startup_plugin_collector.sh'] networks: From 7484d30501fb50c8997e9e3d0489af8eab40f266 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 16:42:43 +0100 Subject: [PATCH 064/287] also notify user if stream is not present at all --- Images/qiita/start_plugin.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Images/qiita/start_plugin.py b/Images/qiita/start_plugin.py index 5afde47..87a61dc 100644 --- a/Images/qiita/start_plugin.py +++ b/Images/qiita/start_plugin.py @@ -15,5 +15,11 @@ print(req.status_code) retvalues = json.loads(req.text) -print("=== request STDERR ===\n%s" % retvalues['stderr']) -print("=== request STDOUT ===\n%s" % retvalues['stdout']) +if 'stderr' in retvalues.keys(): + print("=== request STDERR ===\n%s" % retvalues['stderr']) +else: + print("=== request STDERR: empty ===\n") +if 'stdout' in retvalues.keys(): + print("=== request STDOUT ===\n%s" % retvalues['stdout']) +else: + print("=== request STDOUT: empty ===\n") From 6812b96abdc43ef45b34fa16b9330d54af591bb5 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 16:43:02 +0100 Subject: [PATCH 065/287] adding new plugin --- .../qp-target-gene/qp-target-gene.dockerfile | 70 +++++++++++++++++++ Images/qp-target-gene/start_qp-target-gene.sh | 17 +++++ Makefile | 13 +++- compose.yaml | 23 +++++- 4 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 Images/qp-target-gene/qp-target-gene.dockerfile create mode 100644 Images/qp-target-gene/start_qp-target-gene.sh diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile new file mode 100644 index 0000000..e2d6384 --- /dev/null +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -0,0 +1,70 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# Create conda env +RUN conda create --name qp-target-gene -y -c conda-forge -c bioconda -c biocore python=2.7 SortMeRNA==2.0 numpy==1.13.1 pigz biom-format +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/qp-target-gene", "/bin/bash", "-c"] + +# see https://stackoverflow.com/questions/49940813/pip-no-module-named-internal +RUN wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O get-pip.py +RUN python2.7 get-pip.py --force-reinstall + +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone https://github.com/qiita-spots/qp-target-gene.git +WORKDIR qp-target-gene +RUN pip install biom-format +RUN pip install -e . +RUN pip install --upgrade certifi +RUN pip install pip-system-certs +RUN conda install tornado +COPY trigger.py /trigger.py + +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qp-target-gene.sh . +RUN chmod 755 start_qp-target-gene.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python2.7/site-packages/qiita_client/plugin.py +RUN /qp-target-gene/scripts/configure_target_gene --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-target-gene/" /unshared_plugins/*.conf + +CMD ["conda", "run", "-n", "qp-target-gene", "./start_qp-target-gene.sh"] diff --git a/Images/qp-target-gene/start_qp-target-gene.sh b/Images/qp-target-gene/start_qp-target-gene.sh new file mode 100644 index 0000000..3f814f7 --- /dev/null +++ b/Images/qp-target-gene/start_qp-target-gene.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qp-target-gene + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qp-target-gene; cd / && python trigger.py qp-target-gene start_target_gene /qp-target-gene + +tail -f /dev/null diff --git a/Makefile b/Makefile index c30faa2..c217bd3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,11 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s cd $@/ && $(OPENSSL) x509 -req -in $(CERTNAME)_server.csr -CA $(CERTNAME)_rootca.crt -CAkey $(CERTNAME)_rootca.key -CAcreateserial -out $(CERTNAME)_server.crt -days 365 -sha256 -extfile $(CERTNAME)_cert.conf # === end: create own certificates === +TMPDIR=$(shell mktemp -d) +plugin: Images/qtp-biom/trigger.py Certificates/ + cp -r $^ $(TMPDIR)/ + cd $(TMPDIR) + .built_image_biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh Images/qtp-biom/trigger.py Certificates/ rm -rf Images/qtp-biom/Certificates && cp -r Certificates Images/qtp-biom/ cd Images/qtp-biom && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qtp-biom @@ -31,6 +36,12 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s cd Images/qtp-sequencing && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qtp-sequencing touch .built_image_sequencing +.built_image_target-gene: Images/qp-target-gene/qp-target-gene.dockerfile Images/qp-target-gene/start_qp-target-gene.sh Images/qtp-biom/trigger.py Certificates/ + rm -rf Images/qp-target-gene/Certificates && cp -r Certificates Images/qp-target-gene/ + cp Images/qtp-biom/trigger.py Images/qp-target-gene/ + cd Images/qp-target-gene && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qp-target-gene + touch .built_image_target-gene + .built_image_nginx: Images/nginx/nginx.dockerfile Images/nginx/start_nginx.sh Images/nginx/nginx_qiita.conf cd Images/nginx && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-nginx_qiita mkdir -p ./logs @@ -50,7 +61,7 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_sequencing +images: .built_image_biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_sequencing .built_image_target-gene environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env diff --git a/compose.yaml b/compose.yaml index f6ed81e..7a6a701 100644 --- a/compose.yaml +++ b/compose.yaml @@ -202,6 +202,26 @@ services: networks: - qiita-net + qp-target-gene: + image: local-qp-target-gene:latest + command: ['./start_qp-target-gene.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -219,9 +239,10 @@ services: depends_on: - qtp-biom # one of the plugins - qtp-sequencing + - qp-target-gene - qiita-db # as values in qiita DB might be updated environment: - - QIITA_PLUGINS="qtp-biom:qtp-sequencing:" + - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:" command: ['/startup_plugin_collector.sh'] networks: From 53061c07160e20f3f474e68dc10b38d6599d3b63 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 17:53:06 +0100 Subject: [PATCH 066/287] refactor makefile to avoid code duplication for plugins --- Makefile | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index c217bd3..9aef31f 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,11 @@ PODMAN_BIN = docker buildx CERTNAME=stefan OPENSSL=/bin/openssl +TMPDIR := $(shell mktemp -d) +ifeq ($(origin tmpdir), undefined) +tmpdir = $(TMPDIR) +endif + Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/stefan_cert.conf # === create own certificates === mkdir -p Certificates/ @@ -20,27 +25,27 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s cd $@/ && $(OPENSSL) x509 -req -in $(CERTNAME)_server.csr -CA $(CERTNAME)_rootca.crt -CAkey $(CERTNAME)_rootca.key -CAcreateserial -out $(CERTNAME)_server.crt -days 365 -sha256 -extfile $(CERTNAME)_cert.conf # === end: create own certificates === -TMPDIR=$(shell mktemp -d) +# a general target, executed for each plugin plugin: Images/qtp-biom/trigger.py Certificates/ - cp -r $^ $(TMPDIR)/ - cd $(TMPDIR) + cp -r $^ $(tmpdir)/ -.built_image_biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh Images/qtp-biom/trigger.py Certificates/ - rm -rf Images/qtp-biom/Certificates && cp -r Certificates Images/qtp-biom/ - cd Images/qtp-biom && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qtp-biom - touch .built_image_biom +.built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh Images/qtp-biom/trigger.py Certificates/ - rm -rf Images/qtp-sequencing/Certificates && cp -r Certificates Images/qtp-sequencing/ - cp Images/qtp-biom/trigger.py Images/qtp-sequencing/ - cd Images/qtp-sequencing && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qtp-sequencing - touch .built_image_sequencing +.built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_target-gene: Images/qp-target-gene/qp-target-gene.dockerfile Images/qp-target-gene/start_qp-target-gene.sh Images/qtp-biom/trigger.py Certificates/ - rm -rf Images/qp-target-gene/Certificates && cp -r Certificates Images/qp-target-gene/ - cp Images/qtp-biom/trigger.py Images/qp-target-gene/ - cd Images/qp-target-gene && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qp-target-gene - touch .built_image_target-gene +.built_image_qp-target-gene: Images/qp-target-gene/qp-target-gene.dockerfile Images/qp-target-gene/start_qp-target-gene.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` .built_image_nginx: Images/nginx/nginx.dockerfile Images/nginx/start_nginx.sh Images/nginx/nginx_qiita.conf cd Images/nginx && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-nginx_qiita @@ -56,12 +61,13 @@ plugin: Images/qtp-biom/trigger.py Certificates/ cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita touch .built_image_qiita -.built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh Certificates/ +.built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh + tmpdir=$(TMPDIR) $(MAKE) plugin cp -r Certificates/ Images/plugin_collector/ cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_sequencing .built_image_target-gene +images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env From 74da28385244cdcf3cec5c40f15a5e3f8a464e9b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 17:54:03 +0100 Subject: [PATCH 067/287] ignore src files and tmp Certificates file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 434458f..8d99ff1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ environments/*.env logs/* .built_image_* +Certificates/* +src/* From 0f839bb0dacf1bf113ab3b331d643eda74854f03 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 21:09:14 +0100 Subject: [PATCH 068/287] add new plugin: qtp-visualization --- .../qtp-visualization.dockerfile | 74 +++++++++++++++++++ .../start_qtp-visualization.sh | 17 +++++ Makefile | 8 +- compose.yaml | 23 +++++- 4 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 Images/qtp-visualization/qtp-visualization.dockerfile create mode 100644 Images/qtp-visualization/start_qtp-visualization.sh diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile new file mode 100644 index 0000000..799f10a --- /dev/null +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -0,0 +1,74 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + +# Download qiime2 yaml +RUN wget -q https://data.qiime2.org/distro/core/qiime2-2019.10-py36-linux-conda.yml + +# Create conda env +RUN conda env create --name qtp-visualization -y --file qiime2-2019.10-py36-linux-conda.yml +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-visualization", "/bin/bash", "-c"] + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone https://github.com/qiita-spots/qtp-visualization.git +WORKDIR qtp-visualization +RUN pip install -e . +RUN pip install --upgrade certifi +RUN pip install pip-system-certs + +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qtp-visualization.sh . +RUN chmod 755 start_qtp-visualization.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN chmod u+x /qtp-visualization/scripts/configure_visualization_types /qtp-visualization/scripts/start_visualization_types +RUN /qtp-visualization/scripts/configure_visualization_types --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-visualization/" /unshared_plugins/*.conf + +CMD ["./start_qtp-visualization.sh"] diff --git a/Images/qtp-visualization/start_qtp-visualization.sh b/Images/qtp-visualization/start_qtp-visualization.sh new file mode 100644 index 0000000..ec5e941 --- /dev/null +++ b/Images/qtp-visualization/start_qtp-visualization.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qtp-sequencing + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +cd / && python trigger.py qtp-visualization start_visualization_types /qtp-visualization + +tail -f /dev/null diff --git a/Makefile b/Makefile index 9aef31f..d735080 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,12 @@ plugin: Images/qtp-biom/trigger.py Certificates/ $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` +.built_image_qtp-visualization: Images/qtp-visualization/qtp-visualization.dockerfile Images/qtp-visualization/start_qtp-visualization.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` + .built_image_nginx: Images/nginx/nginx.dockerfile Images/nginx/start_nginx.sh Images/nginx/nginx_qiita.conf cd Images/nginx && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-nginx_qiita mkdir -p ./logs @@ -67,7 +73,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene +images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env diff --git a/compose.yaml b/compose.yaml index 7a6a701..4023430 100644 --- a/compose.yaml +++ b/compose.yaml @@ -222,6 +222,26 @@ services: networks: - qiita-net + qtp-visualization: + image: local-qtp-visualization:latest + command: ['./start_qtp-visualization.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -240,9 +260,10 @@ services: - qtp-biom # one of the plugins - qtp-sequencing - qp-target-gene + - qtp-visualization - qiita-db # as values in qiita DB might be updated environment: - - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:" + - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:" command: ['/startup_plugin_collector.sh'] networks: From ee9a9e61bbf2d06410c82c1a0bcaa5b063bc5c2f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 21:09:32 +0100 Subject: [PATCH 069/287] more debug info --- Images/qiita/start_plugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Images/qiita/start_plugin.py b/Images/qiita/start_plugin.py index 87a61dc..d1df576 100644 --- a/Images/qiita/start_plugin.py +++ b/Images/qiita/start_plugin.py @@ -13,6 +13,8 @@ 'job_id': job_id, 'output_dir': output_dir}) print(req.status_code) +if req.status_code != 200: + print(req.content) retvalues = json.loads(req.text) if 'stderr' in retvalues.keys(): From 05d280e10ddb0048eed4af32673cfd5d7588475f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 21:09:54 +0100 Subject: [PATCH 070/287] more debug info --- Images/qtp-biom/trigger.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Images/qtp-biom/trigger.py b/Images/qtp-biom/trigger.py index 20c2957..e8c9cfe 100644 --- a/Images/qtp-biom/trigger.py +++ b/Images/qtp-biom/trigger.py @@ -39,6 +39,12 @@ def post(self): except Exception as e: self.set_status(500) + # a hack to learn which docker service I am in + plugin_name = "unknown" + for f in glob('/start_*.sh'): + plugin_name = f.split('_')[-1].replace('.sh', '') + break + print("Error in service '%s': %s" % (plugin_name, str(e)), file=sys.stderr) self.write({"error": str(e)}) class RunConfigHandler(tornado.web.RequestHandler): @@ -64,5 +70,5 @@ def make_app(): app = make_app() app.listen(5000) # Server auf Port 5000 starten - print("Server laeuft auf http://localhost:5000") + print("Server laeuft auf http://localhost:5000", file=sys.stderr) tornado.ioloop.IOLoop.current().start() From 8d0887752b114ca48bfbf6c739e022dea8c5d4e1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 21:10:24 +0100 Subject: [PATCH 071/287] ensure that plugin mini-tornado runs in base env to make sure the correct tornado version is used --- Images/qp-target-gene/qp-target-gene.dockerfile | 9 ++++++--- Images/qp-target-gene/start_qp-target-gene.sh | 2 +- Images/qtp-biom/qtp-biom.dockerfile | 7 ++++++- Images/qtp-biom/start_qtp-biom.sh | 2 +- Images/qtp-sequencing/qtp-sequencing.dockerfile | 10 +++++++--- Images/qtp-sequencing/start_qtp-sequencing.sh | 2 +- 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index e2d6384..20beaef 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -23,6 +23,11 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + # Create conda env RUN conda create --name qp-target-gene -y -c conda-forge -c bioconda -c biocore python=2.7 SortMeRNA==2.0 numpy==1.13.1 pigz biom-format # Make RUN commands use the new environment: @@ -42,8 +47,6 @@ RUN pip install biom-format RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -RUN conda install tornado -COPY trigger.py /trigger.py # TODO: should the plugin get the server configuration?! RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg @@ -67,4 +70,4 @@ RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Ente RUN /qp-target-gene/scripts/configure_target_gene --env-script "true" --server-cert /unshared_certificates/stefan_server.crt RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-target-gene/" /unshared_plugins/*.conf -CMD ["conda", "run", "-n", "qp-target-gene", "./start_qp-target-gene.sh"] +CMD ["./start_qp-target-gene.sh"] diff --git a/Images/qp-target-gene/start_qp-target-gene.sh b/Images/qp-target-gene/start_qp-target-gene.sh index 3f814f7..5fdfed7 100644 --- a/Images/qp-target-gene/start_qp-target-gene.sh +++ b/Images/qp-target-gene/start_qp-target-gene.sh @@ -12,6 +12,6 @@ ENV_NAME=qp-target-gene #start_biom https://localhost:8383 register ignored #start_biom http://qiita:8383 register ignored #source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py -source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qp-target-gene; cd / && python trigger.py qp-target-gene start_target_gene /qp-target-gene +cd / && python trigger.py qp-target-gene start_target_gene /qp-target-gene tail -f /dev/null diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index deac39f..511692b 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -23,6 +23,11 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + # Download qtp-biom yaml RUN wget https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml @@ -64,4 +69,4 @@ RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert /unshared_certificates/stefan_server.crt RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf -CMD ["conda", "run", "-n", "qtp-biom", "./start_qtp-biom.sh"] +CMD ["./start_qtp-biom.sh"] diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index 912c38d..1e2d9ba 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -12,6 +12,6 @@ ENV_NAME=qtp-biom #start_biom https://localhost:8383 register ignored #start_biom http://qiita:8383 register ignored #source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py -source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-biom; cd / && python trigger.py qtp-biom start_biom /qtp-biom +cd / && python trigger.py qtp-biom start_biom /qtp-biom tail -f /dev/null diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index 2635b6a..5985300 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -23,6 +23,11 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + # Create conda env RUN conda create --name qtp-sequencing -y -c conda-forge -c bioconda pip pigz quast fqtools python=3.9 # Make RUN commands use the new environment: @@ -37,8 +42,6 @@ WORKDIR qtp-sequencing RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -RUN conda install tornado -COPY trigger.py /trigger.py # TODO: should the plugin get the server configuration?! RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg @@ -61,4 +64,5 @@ RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` RUN /qtp-sequencing/scripts/configure_qtp_sequencing --env-script "true" --ca-cert /unshared_certificates/stefan_server.crt RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-sequencing/" /unshared_plugins/*.conf -CMD ["conda", "run", "-n", "qtp-sequencing", "./start_qtp-sequencing.sh"] +#CMD ["conda", "run", "-n", "qtp-sequencing", "./start_qtp-sequencing.sh"] +CMD ["./start_qtp-sequencing.sh"] diff --git a/Images/qtp-sequencing/start_qtp-sequencing.sh b/Images/qtp-sequencing/start_qtp-sequencing.sh index d3fbf11..d4d0494 100644 --- a/Images/qtp-sequencing/start_qtp-sequencing.sh +++ b/Images/qtp-sequencing/start_qtp-sequencing.sh @@ -12,6 +12,6 @@ ENV_NAME=qtp-sequencing #start_biom https://localhost:8383 register ignored #start_biom http://qiita:8383 register ignored #source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py -source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qtp-sequencing; cd / && python trigger.py qtp-sequencing start_qtp_sequencing /qtp-sequencing +cd / && python trigger.py qtp-sequencing start_qtp_sequencing /qtp-sequencing tail -f /dev/null From 565b8c45999d1d657e73ce2c9dc5d5c7caca588b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 5 Mar 2025 23:54:44 +0100 Subject: [PATCH 072/287] adding plugins "deblur" and "diversity" --- Images/qp-deblur/qp-deblur.dockerfile | 75 +++++++++++++++++++ Images/qp-deblur/start_qp-deblur.sh | 17 +++++ Images/qtp-diversity/qtp-diversity.dockerfile | 72 ++++++++++++++++++ Images/qtp-diversity/start_qtp-diversity.sh | 17 +++++ Makefile | 14 +++- compose.yaml | 44 ++++++++++- 6 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 Images/qp-deblur/qp-deblur.dockerfile create mode 100644 Images/qp-deblur/start_qp-deblur.sh create mode 100644 Images/qtp-diversity/qtp-diversity.dockerfile create mode 100644 Images/qtp-diversity/start_qtp-diversity.sh diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile new file mode 100644 index 0000000..8376971 --- /dev/null +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -0,0 +1,75 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + +# Create conda env +RUN conda create --quiet -n deblur python=3.5 pip libgfortran=3 +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/deblur", "/bin/bash", "-c"] + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN conda install --quiet --yes -c bioconda -c biocore "VSEARCH=2.7.0" MAFFT=7.310 SortMeRNA=2.0 fragment-insertion gcc +RUN pip install -U pip +RUN pip install numpy cython pandas +RUN pip install scikit-bio==0.5.5 +#RUN conda install --quiet --yes -c conda-forge + +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone https://github.com/qiita-spots/qp-deblur.git +WORKDIR qp-deblur +RUN pip install -e . +RUN pip install pip-system-certs + +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qp-deblur.sh . +RUN chmod 755 start_qp-deblur.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python3.5/site-packages/qiita_client/plugin.py +RUN /qp-deblur/scripts/configure_deblur --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf + +CMD ["./start_qp-deblur.sh"] diff --git a/Images/qp-deblur/start_qp-deblur.sh b/Images/qp-deblur/start_qp-deblur.sh new file mode 100644 index 0000000..c1639e8 --- /dev/null +++ b/Images/qp-deblur/start_qp-deblur.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qp-deblur + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +cd / && python trigger.py deblur start_deblur /qp-deblur + +tail -f /dev/null diff --git a/Images/qtp-diversity/qtp-diversity.dockerfile b/Images/qtp-diversity/qtp-diversity.dockerfile new file mode 100644 index 0000000..e2ba8b8 --- /dev/null +++ b/Images/qtp-diversity/qtp-diversity.dockerfile @@ -0,0 +1,72 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + +# Download qiime2 yaml +RUN wget -q https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml + +# Create conda env +RUN conda env create --name qiime2 -y --file qiime2-2022.11-py38-linux-conda.yml +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/qiime2", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN pip install https://github.com/biocore/q2-mislabeled/archive/refs/heads/main.zip +RUN git clone https://github.com/qiita-spots/qtp-diversity.git +WORKDIR qtp-diversity +RUN pip install -e . +RUN pip install --upgrade certifi +RUN pip install pip-system-certs + +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qtp-diversity.sh . +RUN chmod 755 start_qtp-diversity.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN chmod u+x /qtp-diversity/scripts/configure_diversity_types /qtp-diversity/scripts/start_diversity_types +RUN /qtp-diversity/scripts/configure_diversity_types --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-diversity/" /unshared_plugins/*.conf + +CMD ["./start_qtp-diversity.sh"] diff --git a/Images/qtp-diversity/start_qtp-diversity.sh b/Images/qtp-diversity/start_qtp-diversity.sh new file mode 100644 index 0000000..ba217c8 --- /dev/null +++ b/Images/qtp-diversity/start_qtp-diversity.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qtp-sequencing + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +cd / && python trigger.py qiime2 start_diversity_types /qtp-diversity + +tail -f /dev/null diff --git a/Makefile b/Makefile index d735080..5039549 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,18 @@ plugin: Images/qtp-biom/trigger.py Certificates/ $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` +.built_image_qtp-diversity: Images/qtp-diversity/qtp-diversity.dockerfile Images/qtp-diversity/start_qtp-diversity.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` + +.built_image_qp-deblur: Images/qp-deblur/qp-deblur.dockerfile Images/qp-deblur/start_qp-deblur.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` + .built_image_nginx: Images/nginx/nginx.dockerfile Images/nginx/start_nginx.sh Images/nginx/nginx_qiita.conf cd Images/nginx && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-nginx_qiita mkdir -p ./logs @@ -73,7 +85,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization +images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env diff --git a/compose.yaml b/compose.yaml index 4023430..55ed0a0 100644 --- a/compose.yaml +++ b/compose.yaml @@ -242,6 +242,46 @@ services: networks: - qiita-net + qtp-diversity: + image: local-qtp-diversity:latest + command: ['./start_qtp-diversity.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + + qp-deblur: + image: local-qp-deblur:latest + command: ['./start_qp-deblur.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -261,9 +301,11 @@ services: - qtp-sequencing - qp-target-gene - qtp-visualization + - qtp-diversity + - qp-deblur - qiita-db # as values in qiita DB might be updated environment: - - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:" + - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:" command: ['/startup_plugin_collector.sh'] networks: From e5cf9cc2e440aef9c0d57a648c2841313b375722 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 6 Mar 2025 10:14:48 +0100 Subject: [PATCH 073/287] handle case that software is not present at all --- Images/plugin_collector/fix_test_db.py | 44 ++++++++++++++------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Images/plugin_collector/fix_test_db.py b/Images/plugin_collector/fix_test_db.py index 15ae4ef..49084cd 100644 --- a/Images/plugin_collector/fix_test_db.py +++ b/Images/plugin_collector/fix_test_db.py @@ -29,26 +29,30 @@ config['main']['name'], config['main']['version'] ) cursor.execute(SQL_get_softwareID_clientID) - old_software_id, old_client_id = cursor.fetchone() - - if config['oauth2']['client_id'] != old_client_id: - SQL_update = "BEGIN; " - # add in the new client secret - SQL_update += "INSERT INTO qiita.oauth_identifiers VALUES ('%s', '%s');" % (config['oauth2']['client_id'], config['oauth2']['client_secret']) - # add in a new software_id to client_id row - SQL_update += "INSERT INTO qiita.oauth_software VALUES (%s, '%s');" % (old_software_id, config['oauth2']['client_id']) - # remove old client_id - SQL_update += "DELETE FROM qiita.oauth_software WHERE software_id=%s AND client_id='%s';" % (old_software_id, old_client_id) - # delete old client_id client_secret relation - SQL_update += "DELETE FROM qiita.oauth_identifiers WHERE client_id='%s';" % old_client_id - # replace ENVIRONMENT_SCRIPT with the one given in config file - SQL_update += "UPDATE qiita.software SET environment_script='%s' WHERE software_id='%s';" % (config['main']['ENVIRONMENT_SCRIPT'], old_software_id) - # replace START_SCRIPT with the one given in config file - SQL_update += "UPDATE qiita.software SET start_script='%s' WHERE software_id='%s';" % (config['main']['START_SCRIPT'], old_software_id) - SQL_update += " COMMIT;" - cursor.execute(SQL_update) - print(" credentials replaced.") + sql_result = cursor.fetchone() + if sql_result is None: + print(" plugin not (yet) in database.") else: - print(" credentials already up to date.") + old_software_id, old_client_id = sql_result + + if config['oauth2']['client_id'] != old_client_id: + SQL_update = "BEGIN; " + # add in the new client secret + SQL_update += "INSERT INTO qiita.oauth_identifiers VALUES ('%s', '%s');" % (config['oauth2']['client_id'], config['oauth2']['client_secret']) + # add in a new software_id to client_id row + SQL_update += "INSERT INTO qiita.oauth_software VALUES (%s, '%s');" % (old_software_id, config['oauth2']['client_id']) + # remove old client_id + SQL_update += "DELETE FROM qiita.oauth_software WHERE software_id=%s AND client_id='%s';" % (old_software_id, old_client_id) + # delete old client_id client_secret relation + SQL_update += "DELETE FROM qiita.oauth_identifiers WHERE client_id='%s';" % old_client_id + # replace ENVIRONMENT_SCRIPT with the one given in config file + SQL_update += "UPDATE qiita.software SET environment_script='%s' WHERE software_id='%s';" % (config['main']['ENVIRONMENT_SCRIPT'], old_software_id) + # replace START_SCRIPT with the one given in config file + SQL_update += "UPDATE qiita.software SET start_script='%s' WHERE software_id='%s';" % (config['main']['START_SCRIPT'], old_software_id) + SQL_update += " COMMIT;" + cursor.execute(SQL_update) + print(" credentials replaced.") + else: + print(" credentials already up to date.") conn.close() From 344594bc5784d773cbd5faee3a96f085630ebd66 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 6 Mar 2025 10:15:29 +0100 Subject: [PATCH 074/287] adding qtp-job-output-folder and qp-qiime2 plugins --- DemoData/metadata.txt | 43 +++++++++ DemoData/prep_data.txt | 4 + DemoData/zr5156_1V3V4_R1.fastq.gz | Bin 0 -> 176967 bytes DemoData/zr5156_1V3V4_R2.fastq.gz | Bin 0 -> 183106 bytes DemoData/zr5156_2V3V4_R1.fastq.gz | Bin 0 -> 173554 bytes DemoData/zr5156_2V3V4_R2.fastq.gz | Bin 0 -> 179465 bytes DemoData/zr5156_3V3V4_R1.fastq.gz | Bin 0 -> 168374 bytes DemoData/zr5156_3V3V4_R2.fastq.gz | Bin 0 -> 174224 bytes Images/qp-qiime2/qp-qiime2.dockerfile | 87 ++++++++++++++++++ Images/qp-qiime2/start_qp-qiime2.sh | 17 ++++ .../qtp-job-output-folder.dockerfile | 66 +++++++++++++ .../start_qtp-job-output-folder.sh | 17 ++++ Makefile | 14 ++- compose.yaml | 44 ++++++++- 14 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 DemoData/metadata.txt create mode 100644 DemoData/prep_data.txt create mode 100644 DemoData/zr5156_1V3V4_R1.fastq.gz create mode 100644 DemoData/zr5156_1V3V4_R2.fastq.gz create mode 100644 DemoData/zr5156_2V3V4_R1.fastq.gz create mode 100644 DemoData/zr5156_2V3V4_R2.fastq.gz create mode 100644 DemoData/zr5156_3V3V4_R1.fastq.gz create mode 100644 DemoData/zr5156_3V3V4_R2.fastq.gz create mode 100644 Images/qp-qiime2/qp-qiime2.dockerfile create mode 100644 Images/qp-qiime2/start_qp-qiime2.sh create mode 100644 Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile create mode 100644 Images/qtp-job-output-folder/start_qtp-job-output-folder.sh diff --git a/DemoData/metadata.txt b/DemoData/metadata.txt new file mode 100644 index 0000000..0fcf059 --- /dev/null +++ b/DemoData/metadata.txt @@ -0,0 +1,43 @@ +sample_name cage collection_date collection_timestamp comments_2022_05_31 country description dna_extracted elevation empo_1 empo_2 empo_3 empo_4 env_biome env_feature env_material env_package geo_loc_name host_autopsy host_body_habitat host_body_product host_body_site host_common_name host_genotype host_scientific_name host_subject_id host_taxid host_weight host_weight_2022_05_11 host_weight_2022_05_11_units host_weight_2022_05_18 host_weight_2022_05_18_units host_weight_2022_05_24 host_weight_2022_05_24_units host_weight_2022_05_31 host_weight_2022_05_31_units host_weight_2022_06_01 host_weight_2022_06_01_units host_weight_2022_06_02 host_weight_2022_06_02_units host_weight_2022_06_07 host_weight_2022_06_07_units host_weight_2022_06_14 host_weight_2022_06_14_units host_weight_2022_06_21 host_weight_2022_06_21_units host_weight_units latitude longitude mouse_label physical_specimen_location physical_specimen_remaining qiita_sample_type sample_type scientific_name taxon_id timestamp_flashtreatment timestamp_treatment timestamp_tumorinjection treatment tumor_cellline tumor_volume_2022_05_26 tumor_volume_2022_05_26_units tumor_volume_2022_05_31 tumor_volume_2022_05_31_units tumor_volume_2022_06_02 tumor_volume_2022_06_02_units tumor_volume_2022_06_07 tumor_volume_2022_06_07_units tumor_volume_2022_06_09 tumor_volume_2022_06_09_units tumor_volume_2022_06_13 tumor_volume_2022_06_13_units tumor_volume_2022_06_15 tumor_volume_2022_06_15_units tumor_volume_2022_06_17 tumor_volume_2022_06_17_units tumor_volume_2022_06_20 tumor_volume_2022_06_20_units tumor_volume_2022_06_24 tumor_volume_2022_06_24_units zymo_custom_label +6.15299.zr5156.10V3V4 R1C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt 2 Metastasis in Ling UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 37 10090 18.8 18.8 grams 19.9 grams 19.7 grams 21 grams not collected grams not collected grams 21.7 grams 23.4 grams 23.1 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control osteosarcoma cells LM8 108.8 cubic_millimeters 202.14 cubic_millimeters 122.9 cubic_millimeters 355.87 cubic_millimeters 193.21 cubic_millimeters 404.43 cubic_millimeters 225.94 cubic_millimeters 307.72 cubic_millimeters 598.69 cubic_millimeters 758.31 cubic_millimeters 12 +6.15299.zr5156.11V3V4 R1C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt No Metastasis UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 38 10090 19.6 19.6 grams 21.2 grams 21.6 grams 20.7 grams not collected grams not collected grams 21.2 grams 23.4 grams 22.8 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control +CD133 osteosarcoma cells LM8 155.74 cubic_millimeters 205.15 cubic_millimeters 192.87 cubic_millimeters 260.46 cubic_millimeters 231.28 cubic_millimeters 363.82 cubic_millimeters 435.2 cubic_millimeters 334.93 cubic_millimeters 460.53 cubic_millimeters not collected cubic_millimeters 13 +6.15299.zr5156.12V3V4 R1C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 39 10090 18.8 18.8 grams 20.8 grams 20.5 grams 22.1 grams not collected grams not collected grams 21.7 grams 21.7 grams 21.6 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control +CD133 osteosarcoma cells LM8 176.87 cubic_millimeters 102.76 cubic_millimeters 219.75 cubic_millimeters 191.59 cubic_millimeters 190.12 cubic_millimeters 340.03 cubic_millimeters 376.11 cubic_millimeters 230.79 cubic_millimeters 376.8 cubic_millimeters not collected cubic_millimeters 14 +6.15299.zr5156.13V3V4 R1C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt Big Tumour intestine UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 40 10090 18.8 18.8 grams 20.6 grams 20.5 grams 22.3 grams not collected grams not collected grams 22.1 grams 23.1 grams 23 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control +CD133 osteosarcoma cells LM8 156.06 cubic_millimeters 205.73 cubic_millimeters 281.13 cubic_millimeters 281.13 cubic_millimeters 326.98 cubic_millimeters 553.1 cubic_millimeters 546.34 cubic_millimeters 551.07 cubic_millimeters 706.5 cubic_millimeters not collected cubic_millimeters 15 +6.15299.zr5156.14V3V4 R1C4 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt Tumour more bony UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 42 10090 17.6 17.6 grams 20 grams 19.7 grams 19.6 grams not collected grams not collected grams 21.4 grams 21.2 grams 22.9 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 194.26 cubic_millimeters 160.06 cubic_millimeters 131.35 cubic_millimeters 163.2 cubic_millimeters 142.87 cubic_millimeters 127.55 cubic_millimeters 164.85 cubic_millimeters 109.9 cubic_millimeters 131.88 cubic_millimeters 189.81 cubic_millimeters 16 +6.15299.zr5156.15V3V4 R1C4 2022 2022 booster_diet Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt 3 Metastasis UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 43 10090 20 20 grams 21.2 grams 21.8 grams 18.9 grams 19.2 grams 21.5 grams 22.4 grams 24 grams 24.3 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 146.53 cubic_millimeters 164.6 cubic_millimeters 162.81 cubic_millimeters 131.08 cubic_millimeters 105.69 cubic_millimeters 156.06 cubic_millimeters 78.5 cubic_millimeters 78.5 cubic_millimeters 131.88 cubic_millimeters 143.05 cubic_millimeters 17 +6.15299.zr5156.16V3V4 R1C4 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt No Visible Tumour UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 44 10090 17.3 17.3 grams 18.9 grams 21 grams 20 grams not collected grams not collected grams 22.6 grams 21.8 grams 22.1 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 137.85 cubic_millimeters 169.56 cubic_millimeters 165.96 cubic_millimeters 65.42 cubic_millimeters 80.07 cubic_millimeters 65.42 cubic_millimeters 86.35 cubic_millimeters 65.42 cubic_millimeters 78.5 cubic_millimeters not collected cubic_millimeters 18 +6.15299.zr5156.17V3V4 R1C4 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt - UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 45 10090 19.7 19.7 grams 21.1 grams 21.5 grams 20.9 grams not collected grams not collected grams 23.8 grams 22.9 grams 23.3 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 116.52 cubic_millimeters 173.64 cubic_millimeters 188.12 cubic_millimeters 153.73 cubic_millimeters 134.59 cubic_millimeters 257.17 cubic_millimeters 249.11 cubic_millimeters 175.84 cubic_millimeters 175.84 cubic_millimeters 142.5 cubic_millimeters 19 +6.15299.zr5156.18V3V4 R1C5 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 46 10090 20.8 20.8 grams 22.8 grams 21.7 grams 21.7 grams not collected grams not collected grams 23.2 grams 23.5 grams 24.5 grams grams 8.677660635 49.93039264 avg Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 105.35 cubic_millimeters 99.44 cubic_millimeters 158.93 cubic_millimeters 113.33 cubic_millimeters 114.13 cubic_millimeters 148.73 cubic_millimeters 156.65 cubic_millimeters 109.9 cubic_millimeters 109.9 cubic_millimeters 111.03 cubic_millimeters 20 +6.15299.zr5156.19V3V4 R1C5 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 47 10090 17.6 17.6 grams 20.2 grams 21.1 grams 19.6 grams not collected grams not collected grams 22.5 grams 21.8 grams 23.2 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 85.11 cubic_millimeters 135.61 cubic_millimeters 118.88 cubic_millimeters 124.66 cubic_millimeters 86.35 cubic_millimeters 173.89 cubic_millimeters 157.47 cubic_millimeters 109.9 cubic_millimeters 87.92 cubic_millimeters 154.13 cubic_millimeters 21 +6.15299.zr5156.1V3V4 R1C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt - UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 26 10090 18.5 18.5 grams 20.6 grams 21 grams 21.5 grams not collected grams not collected grams 23.5 grams 23.1 grams 23.7 grams grams 8.677660635 49.93039264 avg Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control no Tumor osteosarcoma cells LM8 not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters 1 +6.15299.zr5156.20V3V4 R1C5 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 48 10090 18 18 grams 19.5 grams 19.8 grams 20 grams not collected grams not collected grams 21.5 grams 22.8 grams 22.4 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 127.69 cubic_millimeters 74.87 cubic_millimeters 96.57 cubic_millimeters 149.13 cubic_millimeters 66.06 cubic_millimeters 82.9 cubic_millimeters 117.44 cubic_millimeters 78.5 cubic_millimeters 91.58 cubic_millimeters no visible tumour cubic_millimeters 22 +6.15299.zr5156.21V3V4 R1C5 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 49 10090 17.4 17.4 grams 19.1 grams 19.7 grams 21.1 grams not collected grams not collected grams 20.9 grams 22.4 grams 23.7 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 92.32 cubic_millimeters 112.66 cubic_millimeters 93.4 cubic_millimeters 95.77 cubic_millimeters 95.77 cubic_millimeters 94.81 cubic_millimeters 246.35 cubic_millimeters 146.53 cubic_millimeters 109.9 cubic_millimeters 65.42 cubic_millimeters 23 +6.15299.zr5156.22V3V4 R1C5 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 50 10090 19.2 19.2 grams 20.5 grams 21.4 grams 20.8 grams not collected grams not collected grams 23.3 grams 23 grams 23.1 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 109.24 cubic_millimeters 159.4 cubic_millimeters 180.07 cubic_millimeters 100.89 cubic_millimeters 165.32 cubic_millimeters 182.87 cubic_millimeters 169.06 cubic_millimeters 94.2 cubic_millimeters 91.58 cubic_millimeters 101.72 cubic_millimeters 24 +6.15299.zr5156.23V3V4 R1C6 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 51 10090 17.1 17.1 grams 19.7 grams 20.1 grams 20.1 grams not collected grams not collected grams 22.4 grams 22.5 grams 22.9 grams grams 8.677660635 49.93039264 avg Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 127.48 cubic_millimeters 114.19 cubic_millimeters 117.56 cubic_millimeters 104.22 cubic_millimeters 127.37 cubic_millimeters 131.84 cubic_millimeters 105.35 cubic_millimeters 113.04 cubic_millimeters 78.5 cubic_millimeters 129.31 cubic_millimeters 25 +6.15299.zr5156.24V3V4 R1C6 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 52 10090 17.9 17.9 grams 19.5 grams 20.2 grams 20.2 grams not collected grams not collected grams 22.6 grams 21.7 grams 22.7 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 56.52 cubic_millimeters 151.6 cubic_millimeters 126.35 cubic_millimeters 63.85 cubic_millimeters 71.83 cubic_millimeters 199.98 cubic_millimeters 160.14 cubic_millimeters 94.2 cubic_millimeters 109.9 cubic_millimeters 153.86 cubic_millimeters 26 +6.15299.zr5156.25V3V4 R1C6 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 53 10090 15.6 15.6 grams 18.4 grams 21.3 grams 20.5 grams not collected grams not collected grams 22.6 grams 22.1 grams 23.2 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 65.42 cubic_millimeters 32.5 cubic_millimeters 50.24 cubic_millimeters 34.54 cubic_millimeters 71.24 cubic_millimeters 76.62 cubic_millimeters 99.76 cubic_millimeters 65.42 cubic_millimeters 104.67 cubic_millimeters 64.37 cubic_millimeters 27 +6.15299.zr5156.26V3V4 R1C6 2022 2022 booster_diet Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 54 10090 18 18 grams 20.1 grams 21.5 grams 18.3 grams 20.5 grams 20.8 grams 21.9 grams 23.1 grams 23.3 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 118.44 cubic_millimeters 165.8 cubic_millimeters 175.49 cubic_millimeters 130.62 cubic_millimeters 112.26 cubic_millimeters 167.21 cubic_millimeters 166.68 cubic_millimeters 109.9 cubic_millimeters 128.22 cubic_millimeters 368.43 cubic_millimeters 28 +6.15299.zr5156.27V3V4 R1C6 2022 2022 booster_diet Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 55 10090 16.5 16.5 grams 18.2 grams 20.2 grams 17.9 grams 19.8 grams 19.9 grams 22.5 grams 22.3 grams 23.8 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 FLASH C12 osteosarcoma cells LM8 153.86 cubic_millimeters 195.84 cubic_millimeters 204.65 cubic_millimeters 163.2 cubic_millimeters 125.6 cubic_millimeters 206.86 cubic_millimeters 160.41 cubic_millimeters 128.22 cubic_millimeters 91.58 cubic_millimeters 129.85 cubic_millimeters 29 +6.15299.zr5156.28V3V4 R2C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt No Tumour in Tissue visible UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 56 10090 18.6 18.6 grams 19.3 grams 19.7 grams 20.5 grams not collected grams not collected grams 21.5 grams 21.9 grams 22.2 grams grams 8.677660635 49.93039264 avg Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 65.42 cubic_millimeters 23.55 cubic_millimeters 30.38 cubic_millimeters 39.25 cubic_millimeters 65.42 cubic_millimeters 65.42 cubic_millimeters 112.26 cubic_millimeters 128.22 cubic_millimeters 113.04 cubic_millimeters no visible tumour cubic_millimeters 30 +6.15299.zr5156.29V3V4 R2C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt Metastasis in Kidney UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 57 10090 19.8 19.8 grams 20.5 grams 20.6 grams 19.1 grams not collected grams not collected grams 18.7 grams 22.6 grams 22.8 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 78.63 cubic_millimeters 171.15 cubic_millimeters 175.49 cubic_millimeters 194.52 cubic_millimeters 168.2 cubic_millimeters 272.01 cubic_millimeters 146.53 cubic_millimeters 234.45 cubic_millimeters 179.5 cubic_millimeters 149.67 cubic_millimeters 31 +6.15299.zr5156.2V3V4 R1C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt - UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 27 10090 19.4 19.4 grams 21.9 grams 21.9 grams 21.7 grams not collected grams not collected grams 22.2 grams 23.9 grams 24.6 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control no Tumor osteosarcoma cells LM8 not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters 2 +6.15299.zr5156.30V3V4 R2C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 58 10090 18.4 18.4 grams 20 grams 20.3 grams 20 grams not collected grams not collected grams 22.1 grams 23.3 grams 23 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 143.34 cubic_millimeters 233.78 cubic_millimeters 153.88 cubic_millimeters 126.93 cubic_millimeters 170.75 cubic_millimeters 204.66 cubic_millimeters 194.99 cubic_millimeters 200.96 cubic_millimeters 109.9 cubic_millimeters 172.39 cubic_millimeters 32 +6.15299.zr5156.31V3V4 R2C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt 1 Metastasis in Liver UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 59 10090 17.4 17.4 grams 20.2 grams 19.9 grams 19.1 grams not collected grams not collected grams 22.2 grams 21.6 grams 20.9 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 149.28 cubic_millimeters 149.18 cubic_millimeters 215.36 cubic_millimeters 141.3 cubic_millimeters 152.56 cubic_millimeters 228.69 cubic_millimeters 282.39 cubic_millimeters 263.76 cubic_millimeters 282.6 cubic_millimeters 131.88 cubic_millimeters 33 +6.15299.zr5156.32V3V4 R2C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 60 10090 17.7 17.7 grams 20.3 grams 21.1 grams 20.5 grams not collected grams not collected grams 22.8 grams 23.3 grams 23.5 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 154.74 cubic_millimeters 206.65 cubic_millimeters 211.92 cubic_millimeters 117.44 cubic_millimeters 126.07 cubic_millimeters 229 cubic_millimeters 231.31 cubic_millimeters 179.5 cubic_millimeters 200.96 cubic_millimeters 78.5 cubic_millimeters 34 +6.15299.zr5156.33V3V4 R1C3 2022 2022 booster_diet Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt No metastasis UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 61 10090 16.8 16.8 grams 18.3 grams 20.6 grams 21.1 grams not collected grams not collected grams 20.8 grams 21.4 grams 22.5 grams grams 8.677660635 49.93039264 avg Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control osteosarcoma cells LM8 31.15 cubic_millimeters 45.51 cubic_millimeters 77.39 cubic_millimeters 135.65 cubic_millimeters 253.02 cubic_millimeters 78.5 cubic_millimeters 93.55 cubic_millimeters 65.42 cubic_millimeters 65.42 cubic_millimeters 571.24 cubic_millimeters 35 +6.15299.zr5156.34V3V4 R2C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 62 10090 18.8 18.8 grams 20.8 grams 20.3 grams 19.2 grams not collected grams not collected grams 22.2 grams 23.4 grams 23.5 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 138.55 cubic_millimeters 136.17 cubic_millimeters 271.24 cubic_millimeters 151.85 cubic_millimeters 120.42 cubic_millimeters 188.38 cubic_millimeters 190.76 cubic_millimeters 131.88 cubic_millimeters 131.88 cubic_millimeters 176.87 cubic_millimeters 36 +6.15299.zr5156.35V3V4 R2C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 63 10090 16 16 grams 19.9 grams 20 grams 19.4 grams not collected grams not collected grams 20 grams 22 grams 22.9 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 103.62 cubic_millimeters 178.72 cubic_millimeters 178.59 cubic_millimeters 230.7 cubic_millimeters 217.08 cubic_millimeters 187.27 cubic_millimeters 297.67 cubic_millimeters 251.2 cubic_millimeters 251.2 cubic_millimeters 402.97 cubic_millimeters 37 +6.15299.zr5156.36V3V4 R2C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 64 10090 18.4 18.4 grams 21.3 grams 20.8 grams 19.6 grams not collected grams not collected grams 22.4 grams 22.7 grams 23.3 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 180.32 cubic_millimeters 210.68 cubic_millimeters 233.35 cubic_millimeters 113.01 cubic_millimeters 165.79 cubic_millimeters 341.08 cubic_millimeters 242.88 cubic_millimeters 226.08 cubic_millimeters 167.47 cubic_millimeters 199.86 cubic_millimeters 38 +6.15299.zr5156.37V3V4 R2C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 65 10090 16.5 16.5 grams 19.5 grams 19.7 grams 19.1 grams not collected grams not collected grams 21.1 grams 22.1 grams 22.6 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 165.99 cubic_millimeters 121.47 cubic_millimeters 226.21 cubic_millimeters 128.58 cubic_millimeters 146.91 cubic_millimeters 169.3 cubic_millimeters 187.2 cubic_millimeters 113.04 cubic_millimeters 131.88 cubic_millimeters 381.51 cubic_millimeters 39 +6.15299.zr5156.38V3V4 R2C3 2022 2022 booster_diet Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 66 10090 16.6 16.6 grams 20.2 grams 22 grams 19.8 grams 20 grams 21.6 grams 23.1 grams 22.7 grams 21.9 grams grams 8.677660635 49.93039264 avg Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 140.17 cubic_millimeters 116.58 cubic_millimeters 158.66 cubic_millimeters 147.8 cubic_millimeters 132.84 cubic_millimeters 244.21 cubic_millimeters 171.44 cubic_millimeters 175.84 cubic_millimeters 113.04 cubic_millimeters 376.8 cubic_millimeters 40 +6.15299.zr5156.39V3V4 R2C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 67 10090 16.3 16.3 grams 19.5 grams 19.8 grams 19.3 grams not collected grams not collected grams 21.8 grams 22 grams 24.4 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 65.42 cubic_millimeters 153.15 cubic_millimeters 234.45 cubic_millimeters 138.16 cubic_millimeters 114.13 cubic_millimeters 188.11 cubic_millimeters 178.59 cubic_millimeters 175.84 cubic_millimeters 109.9 cubic_millimeters 137.01 cubic_millimeters 41 +6.15299.zr5156.3V3V4 R1C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt - UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 28 10090 17.6 17.6 grams 19.8 grams 20.4 grams 20.2 grams not collected grams not collected grams 20.6 grams 21.9 grams 24.4 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control no Tumor osteosarcoma cells LM8 not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters 3 +6.15299.zr5156.40V3V4 R2C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt Metastasis Intestine UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 68 10090 18.9 18.9 grams 20.5 grams 22.2 grams 22 grams not collected grams not collected grams 23.5 grams 23.1 grams 23.9 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 109.9 cubic_millimeters 164.85 cubic_millimeters 210.05 cubic_millimeters 137.01 cubic_millimeters 142.43 cubic_millimeters 177.77 cubic_millimeters 254.34 cubic_millimeters 251.2 cubic_millimeters 175.84 cubic_millimeters 339.12 cubic_millimeters 42 +6.15299.zr5156.41V3V4 R2C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 69 10090 17.8 17.8 grams 19.9 grams 20.7 grams 19.5 grams not collected grams not collected grams 22.1 grams 22.4 grams 22.6 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 109.9 cubic_millimeters 165.2 cubic_millimeters 155.43 cubic_millimeters 165.53 cubic_millimeters 126.42 cubic_millimeters 138.79 cubic_millimeters 217.92 cubic_millimeters 263.76 cubic_millimeters 109.9 cubic_millimeters 171.88 cubic_millimeters 43 +6.15299.zr5156.42V3V4 R2C3 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 70 10090 17.2 17.2 grams 20.1 grams 21.3 grams 21.2 grams not collected grams not collected grams 23.2 grams 22.9 grams 24 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 133.71 cubic_millimeters 138.87 cubic_millimeters 124.66 cubic_millimeters 159.75 cubic_millimeters 135.05 cubic_millimeters 260.46 cubic_millimeters 190.49 cubic_millimeters 293.07 cubic_millimeters 263.76 cubic_millimeters 117.75 cubic_millimeters 44 +6.15299.zr5156.4V3V4 R1C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt - UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 29 10090 17.3 17.3 grams 18.3 grams 22.3 grams 22.1 grams not collected grams not collected grams 23.6 grams 26.2 grams 26.1 grams grams 8.677660635 49.93039264 2 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control no Tumor osteosarcoma cells LM8 not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters 4 +6.15299.zr5156.5V3V4 R1C1 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt - UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 30 10090 17.3 17.3 grams 18.5 grams 19.1 grams 20.1 grams not collected grams not collected grams 22.4 grams 22.7 grams 21.7 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control no Tumor osteosarcoma cells LM8 not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters not applicable cubic_millimeters 5 +6.15299.zr5156.6V3V4 R1C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt No metastasis; small primary Tumour UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 32 10090 15 15 grams 15 grams 16.6 grams 17.3 grams not collected grams not collected grams 19.1 grams 18.9 grams 18.4 grams grams 8.677660635 49.93039264 1 Links Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control osteosarcoma cells LM8 170.44 cubic_millimeters 202.22 cubic_millimeters 212.84 cubic_millimeters 112.26 cubic_millimeters 176.31 cubic_millimeters 229.93 cubic_millimeters 242.48 cubic_millimeters 200.96 cubic_millimeters 301.44 cubic_millimeters 109.9 cubic_millimeters 7 +6.15299.zr5156.7V3V4 R1C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt Lot of metastasis; Big Tumour in Liver and Intestine UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 33 10090 17.1 17.1 grams 16.6 grams 18.8 grams 19.4 grams not collected grams not collected grams 20.2 grams 19.4 grams 20.2 grams grams 8.677660635 49.93039264 1 Rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control osteosarcoma cells LM8 153.83 cubic_millimeters 205.1 cubic_millimeters 181.32 cubic_millimeters 300.98 cubic_millimeters 378.33 cubic_millimeters 520.28 cubic_millimeters 487.22 cubic_millimeters 575.67 cubic_millimeters 898.04 cubic_millimeters 590.12 cubic_millimeters 8 +6.15299.zr5156.8V3V4 R1C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt Big Tumour intestine; Lot of metastasis in Lung; Metstatsis intestine and Kidney UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 35 10090 16.7 16.7 grams 16.5 grams 18.5 grams 19.4 grams not collected grams not collected grams 20 grams 20 grams 21.2 grams grams 8.677660635 49.93039264 1 Links 1 rechts Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Control osteosarcoma cells LM8 124.63 cubic_millimeters 222.98 cubic_millimeters 247.71 cubic_millimeters 230.79 cubic_millimeters 240.31 cubic_millimeters 267.08 cubic_millimeters 354.32 cubic_millimeters 226.08 cubic_millimeters 179.5 cubic_millimeters 372.75 cubic_millimeters 10 +6.15299.zr5156.9V3V4 R2C2 2022 2022 Germany FLASH vs conventional irradiation therapy TRUE 134.5 Host-associated Host-associated (non-saline) Animal (non-saline) Animal distal gut (non-saline) urban biome animal-associated habitat feces host-associated Germany:Hesse:Darmstadt UBERON:feces UBERON:feces UBERON:feces mouse C3H/He Mus musculus 36 10090 19.3 19.3 grams 19.8 grams 20.6 grams 19.3 grams not collected grams not collected grams 22.5 grams 23.2 grams 23.7 grams grams 8.677660635 49.93039264 avg Germany FALSE feces feces mouse gut metagenome 410661 2022-05-26 2022-05-26 2022-05-19 Konventional C12 osteosarcoma cells LM8 140.17 cubic_millimeters 117.7 cubic_millimeters 147.8 cubic_millimeters 145.13 cubic_millimeters 130.56 cubic_millimeters 194.29 cubic_millimeters 214.02 cubic_millimeters 200.96 cubic_millimeters 175.84 cubic_millimeters no visible tumour cubic_millimeters 11 diff --git a/DemoData/prep_data.txt b/DemoData/prep_data.txt new file mode 100644 index 0000000..6ea0328 --- /dev/null +++ b/DemoData/prep_data.txt @@ -0,0 +1,4 @@ +sample_name barcode center_name center_project_name experiment_design_description instrument_model library_construction_protocol linker pcr_primers platform primer run_center run_date run_prefix sequencing_meth target_gene target_subfragment +6.15299.zr5156.1V3V4 not provided Zymo Research Corporation zr5156.16S_221128.zymo FLASH vs conventional irradiation on gut microbiome Illumina MiSeq DNA Extraction: One of three different DNA extraction kits was used depending on the sample type and sample volume. In most cases, the ZymoBIOMICS®-96 MagBead DNA Kit (Zymo Research, Irvine, CA) was used to extract DNA using an automated platform. In some cases, ZymoBIOMICS® DNA Miniprep Kit (Zymo Research, Irvine, CA) was used. For low biomass samples, such as skin swabs, the ZymoBIOMICS® DNA Microprep Kit (Zymo Research, Irvine, CA) was used as it permits for a lower elution volume, resulting in more concentrated DNA samples. Targeted Library Preparation: Bacterial 16S ribosomal RNA gene targeted sequencing was performed using the Quick-16S(TM) NGS Library Prep Kit (Zymo Research, Irvine, CA). In most cases, the bacterial 16S primers amplified the V3-V4 region of the 16S rRNA gene. These primers have been custom-designed by Zymo Research to provide the best coverage of the 16S gene while maintaining high sensitivity. Fungal ITS gene targeted sequencing was performed using the Quick-16S(TM) NGS Library Prep Kit with custom ITS2 primers substituted for 16S primers. The sequencing library was prepared using an innovative library preparation process in which PCR reactions were performed in real-time PCR machines to control cycles and therefore limit PCR chimera formation. The final PCR products were quantified with qPCR fluorescence readings and pooled together based on equal molarity. The final pooled library was cleaned with the Select-a-Size DNA Clean & Concentrator(TM) (Zymo Research, Irvine, CA), then quantified with TapeStation®(Agilent Technologies, Santa Clara, CA) and Qubit® (Thermo Fisher Scientific, Waltham, WA). GT FWD:CCTAYGGGDBGCWGCAG; REV:GACTACNVGGGTMTCTAATCC Illumina CCTAYGGGDBGCWGCAG GSI Helmhotzzentrum fuer Schwerionenforschung GmbH 2022-11-28 zr5156_1V3V4 Sequencing by synthesis 16S rRNA V3 +6.15299.zr5156.2V3V4 not provided Zymo Research Corporation zr5156.16S_221128.zymo FLASH vs conventional irradiation on gut microbiome Illumina MiSeq DNA Extraction: One of three different DNA extraction kits was used depending on the sample type and sample volume. In most cases, the ZymoBIOMICS®-96 MagBead DNA Kit (Zymo Research, Irvine, CA) was used to extract DNA using an automated platform. In some cases, ZymoBIOMICS® DNA Miniprep Kit (Zymo Research, Irvine, CA) was used. For low biomass samples, such as skin swabs, the ZymoBIOMICS® DNA Microprep Kit (Zymo Research, Irvine, CA) was used as it permits for a lower elution volume, resulting in more concentrated DNA samples. Targeted Library Preparation: Bacterial 16S ribosomal RNA gene targeted sequencing was performed using the Quick-16S(TM) NGS Library Prep Kit (Zymo Research, Irvine, CA). In most cases, the bacterial 16S primers amplified the V3-V4 region of the 16S rRNA gene. These primers have been custom-designed by Zymo Research to provide the best coverage of the 16S gene while maintaining high sensitivity. Fungal ITS gene targeted sequencing was performed using the Quick-16S(TM) NGS Library Prep Kit with custom ITS2 primers substituted for 16S primers. The sequencing library was prepared using an innovative library preparation process in which PCR reactions were performed in real-time PCR machines to control cycles and therefore limit PCR chimera formation. The final PCR products were quantified with qPCR fluorescence readings and pooled together based on equal molarity. The final pooled library was cleaned with the Select-a-Size DNA Clean & Concentrator(TM) (Zymo Research, Irvine, CA), then quantified with TapeStation®(Agilent Technologies, Santa Clara, CA) and Qubit® (Thermo Fisher Scientific, Waltham, WA). GT FWD:CCTAYGGGDBGCWGCAG; REV:GACTACNVGGGTMTCTAATCC Illumina CCTAYGGGDBGCWGCAG GSI Helmhotzzentrum fuer Schwerionenforschung GmbH 2022-11-28 zr5156_2V3V4 Sequencing by synthesis 16S rRNA V3 +6.15299.zr5156.3V3V4 not provided Zymo Research Corporation zr5156.16S_221128.zymo FLASH vs conventional irradiation on gut microbiome Illumina MiSeq DNA Extraction: One of three different DNA extraction kits was used depending on the sample type and sample volume. In most cases, the ZymoBIOMICS®-96 MagBead DNA Kit (Zymo Research, Irvine, CA) was used to extract DNA using an automated platform. In some cases, ZymoBIOMICS® DNA Miniprep Kit (Zymo Research, Irvine, CA) was used. For low biomass samples, such as skin swabs, the ZymoBIOMICS® DNA Microprep Kit (Zymo Research, Irvine, CA) was used as it permits for a lower elution volume, resulting in more concentrated DNA samples. Targeted Library Preparation: Bacterial 16S ribosomal RNA gene targeted sequencing was performed using the Quick-16S(TM) NGS Library Prep Kit (Zymo Research, Irvine, CA). In most cases, the bacterial 16S primers amplified the V3-V4 region of the 16S rRNA gene. These primers have been custom-designed by Zymo Research to provide the best coverage of the 16S gene while maintaining high sensitivity. Fungal ITS gene targeted sequencing was performed using the Quick-16S(TM) NGS Library Prep Kit with custom ITS2 primers substituted for 16S primers. The sequencing library was prepared using an innovative library preparation process in which PCR reactions were performed in real-time PCR machines to control cycles and therefore limit PCR chimera formation. The final PCR products were quantified with qPCR fluorescence readings and pooled together based on equal molarity. The final pooled library was cleaned with the Select-a-Size DNA Clean & Concentrator(TM) (Zymo Research, Irvine, CA), then quantified with TapeStation®(Agilent Technologies, Santa Clara, CA) and Qubit® (Thermo Fisher Scientific, Waltham, WA). GT FWD:CCTAYGGGDBGCWGCAG; REV:GACTACNVGGGTMTCTAATCC Illumina CCTAYGGGDBGCWGCAG GSI Helmhotzzentrum fuer Schwerionenforschung GmbH 2022-11-28 zr5156_3V3V4 Sequencing by synthesis 16S rRNA V3 diff --git a/DemoData/zr5156_1V3V4_R1.fastq.gz b/DemoData/zr5156_1V3V4_R1.fastq.gz new file mode 100644 index 0000000000000000000000000000000000000000..4b605c3d22e6869d23b5fb5128bf09786bbfde2c GIT binary patch literal 176967 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 z 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 h#ylZ#*`4u#>o zW79BMTzR9p)2?Z2t&x)szj)O&;QMGnsqQX_s5(%Fu+_og8XWTSewc2q zGMsvIqJ7!*-t>d%uf|-%C{N6S3HB(vTK3l=_^x!qH?q90qiUsEagtp#%fZ82p>S{7 zFJ3Ro&b83u@>r#TI zl$Nm$gk%h`Ye*x(Rc5G$Me#hU|DLmVU^wR;hH&=vHa+}h&h}wg!X~Rs-s)|EmlO|E zn4dR-qgw=C=07a(vecqp2)xX%1YVZOqZlvd#8pm(%-@7}UWfj#pV{*@?yvL{yA|da z5}Ze!Uhg9~ABP($T?K#fUU?jNFuiZIN5O%iZwA>raQ3gw;G~X&(+FR9RHOuESJkc85 zSG;sL?R1CivTkXe;hA5@@RxQu|8Rz9nqCsq-3wy+GSB1OR$ouGgc!m@2zO?&$U+}` zJ_{5^ZGE@Q*_!maE)Fz4b{^N41s=S2=@M_;P#~iXx8!&Me;M3c)**wUN7~yJwXkB# zJTiz2-SXh_yvxPds)B`9!~bvq!uLai^AWh6G3%O6DSI`@t}q1LA5qfeDwpjED?>$5 ze->3yoX>elGYaOGvyMUrit~)LgGAFn9@*f=6NqqBTIEpgxBxt}asgLrbZF5Y|I%l}S)Y+Pcs%Gd_Dv&y8}x_Zm$d1g87 zx@T~+qV6u8ItgbHVuK^gm{J56>PaoE zMS`zR{T?A165Ja_C=%AAg`O#3p-!fGiMQI}yoDGps`?+!;Z9$%G!8KQkByei&oFqR zyx-M;(hGMOeA*JojUyD*;&v2`wegrNa@BX4Q{OS9wYD)wT$Y3Ju-QY(8UZyknRbDe z12V#*f`0GQpf}Ray-jRN2)CjPVsPA)fF7>nXd(d;+wJ3M0mbyCACoYaoB9Ah1vtP? z>#`q9iL!tNuAA_s1}AxS1#dd6?|_9iaEltt;*-Qa5Z4IS;C?v#QEd5Kc}s2X@inSv7K0<#Z#&d#{^ zguvB!+qYO64W|{F<=3jz|FP84{&H$L{WP^qrSv_$3=MPDQrouxqeTk8xXHb1y{nsV z(itJ$U|c=s{moVm<$8AzT5$ z5DhrL#r0(4Sf4q~Ke^I97+cFa@3minQ&70wQ4W|o4%QM~)l6yt@4-MKaBdBjLX{1| zCOlL_FgAh^xPBPHkk4o};Ats+PBYfYE&X+G`MhFzXag)2%XIfOUZ-}= zli4!65!wzF%l!<`{UGkI9WSE))6-#ERnilVIXvgr5w{k%PV96s$8d3%xVkJP#*s@l zy^QQY>YX-En8CQ@gbaay=e!=maw1c z9eS?g+@o?AMJ|STYqMM$GNSQbl0b3BXKN@~eRw=!{qeS{)Gd!5zK3sCJpPV_qzCAH zYQbEUTMuOt*3fdiozR6^x~(+s7xmJtGv9s)O+W*Vh#_r`idv%=PI2H;wMY530oBhd zRbbNv%EFXD&j&D_LxH=QHRs55AfBX*00%dW>u}SWD)m`8oHP|dA6|aT!~fKL_|MSr zKQ$k|5}w!_99iHaEMEx#@1J%rL^jqWj@w^=r#9~J>{Ay7R-=tn$-7LBLTX;crylP5o!Wv0_dyBhra0O6zu#^Wm- zp74y8r5Fr^n*?|_vr3vAwX$$;bCuH^SWumQHZ38-Y}pemAIjn3nSV$*JT|F)8(dy* z!KJ;ET3x94k4mk^sP?fO9(;Hd+Lf4w^y@St#A4l6$XT=4JgP{adLJ7n*GzXL?NNy> zPHfM)M&aEk#j&t>KXKJh0##OhDBdqzX9`Uj!5(VgpQP)2lso85kol#irTwIxS3DCk zt&GpIQh~wN1FcfddDnYIDxFXq4+E!+o0V&>$50QSy2fBl9E@Qt+pJESq)}ltDX9`v zU8R6Q3Y-QdEfJ9f1quL3!#QOntjA3*X`WJ^kh0RBZ4WOiq)`A%_P6=)&`bN@<-=n_ zY%7P~O;m-zL!b88!4&8kC5?XG<67%N6-7;lx-TES4DG#lNakjtS&vu+0 zS`g^g?v1_9>Nf6p%cXA)eBf&$Ujf(Aa|hBy&ld$$Mg;=j z(OOPZET01e`ML*B3|cU)V`vF}JZE=NR*a|!1hLobR09GJM zMV=tN!LnnLqx^49DVLgAOV6MA@S5WckErXnuv|JVUyYXCLd%%6d|Tp~@8Zf}74Ha- z{U)ybfbhg3=F(3z+gn^|cX4I>qTy|@bq=o#rgQTU~B`vQ%rXILtxR(RPuC^Nb z?W#4KG}?RjKdl*|5J9>|J?DXz9MGD!+-qr}Bpk$@PK{f7$oaMMDAN;@rXawXNoBzb z8r)OQflKSU;Cxtbj#viJ;^uo_DBPhJ*4-+L0tFN}xgLT1m|={-P0tmhRZ{G zCxujm%8!I+QZo|52ESe#!qZ9Bt&ht|7ws%Gk6w^-MR8S> z#-+@y03xKMQg#q$tccSxAy|y8ff_0D(P)_vSP$nf(nEjwipM=9-Ct4RiT?bd!t+vv zdfrudg0Y-;#xnMX#`xqKdH$vzc#N~-C!(o}?AZrxtU1(B#>p@HcF^LXEalvsfQ}mv zOytB+*H?%^Mxx%ST>4YRPn!2Y&8Jz%K2AQO9t-~3avQ&tKoYo>IiOj`4TpsBo2 zLM$hgqPMB8gAN#CX=*5|~tZQOtMZ4mpkFlFthBctBJ0eDCBEt5rOb&p+fV)UzuAh!QV@YJCY z-ZXBKZX&YDT9@YJTq^_C)oN+g0B+uL9N{_;!HN_ z`SQtXiIO)(0kEvzhnDk)_3)duyuP-U0k88iJ{HX7n$h0F&+XwC6Y{IMbjwiib$RaI zT!wEp!pp@D@{kw3J}Fbrs|UZ%E7QKN1@UW48Z9aH>mtADR^-o{x!l9D$CmO93o&QO z?Lhq`Cecj!aOykRcm8xb^%@OgQ}sE(L8+=&E{Dr|uyccJ2Pbk|OO^o;g8Tq>I(EvP z9HDuB;+*9Cl$)%}X!b>#Q*%01I3@das=hMfT=pg5@#|Eavh1tWzC$fQWb^Z zm-7W^HYsoroUoMPY7-hp!Y}Z6IfoC=VGkPkaTEYPe^hzolnR99`}C0guird+U1QBP zr}~54L)#S3Z3)V*dngi-Bg?jY8uZk>-L^j3I0rjDoIM7|KHXNDteUFpqO%4bx!fc) z!<0|-`yyU~)M#QGL5hiZj0iFTrj7yRYiuyWUlPrFYehyN2=JQV~iMs^R zP2=VGI4)%G@EX1COIdY)_rVxAP~+!(x78HIF`k?{YEL)Y3?}}E`5x?T3$1d~>{Q5F z4)vu&onMA)={=6qnt_!q4&?|nYU{gBI3|Pvvk!iJmLtTI3L;R+Ao^@W^N=MxQKY0w zOQMLx?u|;SVHCVnQWQx}WrERVm7dRMMm`#OY=}Tu()Vf__MarSdi^%G{8RJc_`)+R zU(=s;dCu;H*eUGB$J2dy7YwTep^yL*zbx6YuWIg7P!z^+Tj?_O|ST z)Zhf+pvFylU5jP$Fc}V9Wx_t+20&UQiJ*-dr>JcR_o=_EcBHWgMeCKN3KKrY*nz15 zm^U>_CuLG4z_=OU$`F;3gjq_pq8yh-rHsf=lId_cocSFrS2p`O<+=V0<(Z!-&-Fd! zxjw_vF0j1D7P}oR-F2H6+F)rPU}^7R8A2Dgz;g5CQATS|dEB;1MDFOG{>5FNSh}Y zlw?EhO{l`sBZi?Er()2_>|n8h<0B^C@DgFkew6YYuf&}fdHng#S}sl;ArmCd@3QHC zc?6r+M(Rm0oM<$RwJdxH!K0|fIy%?) zwVA@;k?~+-wHJvv3xQ0g!Zr7Jr_uls_d(jlvJzMe79WW+JmEwesjR{Y-H(PIi(oCA zf5^bZ^>3cVeMx!V4@}&aF1|bb(o}))825WZW2exB_39_!#+^#L9Twt|We+A6l*DS`wevfr(vD+gcL8YqkvE&Yx-2@SirhV?R;&*@k;- zIa-`9da{;SxHP%EayISFG*VBjs;o9J6bj3 zEYA8>?^`vNhRY@1e86Sc5p|Etn-`yVUi?;hbUR$mKec`IvD$siVD1x6-0z?F)7r2W zhHxFkvh#eBJ3_y-v*B)t+NEMz?RkLZ(&fq1rm1yR)!hJ8xu%*?(HCMUh-up-F9DAL zGUg`ka@lH>#R@k_Dv65yMM9M{MB?6_p$hv;2Mzc$3Gg6k1srWDG%+a!SOO!jFsu35 z#6*cZq5zg}t301lp6d@(d9FuQ9(PpbiAnL-aJ|MBjvuM=%xje=)sbo_YZ*?vIFCh4G8_y1w&%Rtg*uev{7!(Jd zvzt@Di!GbUV?$BngDTeSm08Q_%VP2MXnNtJ6%E6)9*rzp+CA#n*fC6`TLMt{+s0z! zFikx;`8G*dV{7Ah)As!!aD7x?VZ)^hsZP=WD|Z8qf{&Kjl+l`|xaU!GV>Dx04~hX1 zDif8aD#VzB)d?U}TkC=Fh>A#{>z`<1Q9%KfTwVyMbmKFm@nAQ_^ra*YKixRao#}xl!RIV=0`;`h zJpga)kzga+ag#B#Wo@2IE|h78pa+5q1qr3P1?UafjXnsS z=BQVFjy=FQPDU7DPl}*Pos;C#Z9JqD6n*$Nx|Vm-|Njah|JXG7vqJvyzQG9~EWPtL z6K3!Fdp4r6e1iE&BqnBGdYrAlWrmiTx%U8{nfF`ras-FmuXS&Z(`A^A$AZu3rZ6X) zcjLIW0EZHz4{tQAQ~GJ5V&vQzTiZIrIM(CPO{--potGj3e_b0OMhR_Af@|{%ivD@> zbzvM>t|@DqFRTQSbCXEraSasJMi*QZgi<*WG;VM|LLu5r8Vcblm`!C0EogbUkZ0yuhfyjj=%(_w^)%7@tZ;IM*bhj49j^!U|3O@ z=(AnT4PgRc$;$W1bo`tAf(Y=M_B$254nyz<~p}`qO%9-q3Izc z+#zk}fc@|tfPq{0U{_7j-nOy3xSVgJXn*rW}C(pys!;QU{8G%dkMk?07jtZjhiJB zBL%pnb}$2>S~A8cHv?D9Xx}2+)~F!3NydP^Oe!-7feO|r)+Uwu2$Ynv8bNuGvvmJ! z$su=SFh5BS?eVks=XW11U61ps#5(z9W-N#Wgz90qK5VufHzsaldlB+&kG(w}rz+g4 zT8-k-yE!sHhf&zpPi&fW@b**ORE|Fh+?G>WcPB1I|z;V8Ck>CUzQeX%Y4~?W?MIIrvirl) z#(6hc@zBb#Kh52J=I2z((J9}q60G=!U_My3$r$Sg0>nj^z+=<^Ktp~0*r5T=p2$o( zo(t(nQ{gHeVR1|8phHB7?<)bJqrmPUskF|eHs|zwso_qfBnc6KTNPT=tB-^WNKs;B z*|4`Qz;>Ylzkj^!`d8P(KSZH>lMLFS@UeU7$LirrfBB;@(9v;>w)G`}WO`I!^o=|X|2#3s0p=6H&-L?_;S+nGLp zW-Z-!unZXahKN70o9hEEpV`e3F0T=n*Z1}C8xfC$?N$%BYYaTcr}2vAJGkL8IB|~+ zkV^+d)Ts#m*#*tM22(!(l9N06>4dMzssV?pyvMx|nBc+6BkpX1KQYd;&SBxnG-nV4 zHZs>>j{d{mwP-hrBhlXhf^9$oBq2*k0`UX>|8LnUNnrd)!c2F1cJ?eYIf-qI-N|)5 zZ`~@1>urH@6{VFUFL8|%zRG0h@uQRW1ZtJl!B`IOZ)B(aHhLp3%eW7d72p)#evUPnU7?ntrT;(STFSM(WqM79-$jy`yMx*NVzeOq?SQs zBkmf-rQsEW$g?TWO)F79ogQiN@QOU6^1ppv;`d}cM@vNCWIUg(J^9kF|JBN7DD?PV zN0<7^B<^D^etLc=EWurtZd3q#9QAc-6(16qbIU7(3|doV4W!v%hzERk}Qb^s6hCKWbExjcKK-nJK)O@^TdE48{+nbW5`{9!1ZMBuR=aS`etYqn2;)~vb z>f60!xpscso9d9iSG*VZK}1m%zxr4@$AT2`@Vimd9$J5?rSpu{`-bnQz9B*jKsw=2;~cYfO zi#z$?Tn_n6IU*!y$NP5f2qy*P+Gc=Ap&hQ{skrv_Whey$DB`jmi&ATPW;Myq9Xa>9 z%P(0+6fI9&5y*-@s;Yso@*;}Sq1IL2b(~WU0b`CbzvuQ$WtA};06)x5l)FiiYfK6C`({aU&BI1bomfM6b{u73UK0G-VO?a#SZtBd2OqKLlzWm zY~Apz&S+gyT|=gBPTf_q+xqa4m zeD3(%)`}&<_-~`~#elw^@?vCnmCMvWkL&v$lB+3{GuxfZkEl$;W`5h-gG0HfLutnd zNu%mMX!-&qEA1;@buC(9+it#o@@v2{Gbll<@~}|7nnd(c$Gp1L4tU3iwXKPA%8Mn;^T^v zLw>e>M=z`rQ$47zZl%r`3JeHpAg5ufMgH&{KQl$a`?}U1a0i)p)3I7;)1hz+#F9cb zebcE*Sokk%nQ3Ho%E}Uw_Ofjn6gX%*(dCCK={9X z67v%{o%e4*?UOq76yG$SA$B~W@kuCQ|H@CeUtM_40h4xFB28nOf)hs+E7f&v3s{^& zMjk4X8flcG4?8KCTUar$0ehoi4;0svl98Z^GZnfQJrdch<)PP82?3Yr=vkP_C@*z` zL?TK7ndKqnAwqEsm(<^shaxPWwKR6HynP*6#~>t!10cT8OFLYKj69f2v&(oEbKf9-Tf5Yy2dD($T(HkYT?U(@1OmQI@@{^`z z(r$({oH4`3qJlI>h5!;HMaar)#!*WZavW`imR@vf0HdrLg)K~tJM<_+u@}gGPTkQl z+!{xCNb@bx@`*aMs}3!@geNUM**F@XEj{^z`Hk5zhs=&SbkA>0tO`8mH=zggKCWCI z^sxR05VvEi5`Ep_emJJ*?&1>J=6ArlWmYKYwiZR&QrEQh1L_%qw^zOww3ig;Cm`qyMiIgRYI*?} zAHaO(4KK5-$zp-%NQb9s@o`4Tuln#*9)G{MY>ntlYOV)+x%zOIs?>L58R~<#A2pVt zp!wv)mn4*N-!~CHDXG;Mk-s;V(TM{r=UpoDOJ?)w$exzub zN=q(XHeM-(mV90(z}DkaQQvrA;5ecYIIgI%}fq3lK>hyr~;gRfsD4P z7$6+AjpiHxluJW8TGdrn_Epp4Vx9rJ;@Rm`g0B|b7@JX2@r)6Mt#C@K$jdy$|LqCF zlKxX$Pks+A-QAsdvg@l8PjA>fEaKVdzxPS-&57@_?!`PhaTDvY>ucgK<`&39VbnTQ z3FU0!K6&r_suZ|0dMix>p&}(_?R;hZEDREFj=h#}6Q0DVh}CW6Q1YP63LgMvaoZ?z z(tIDumf;G8CnP?~e+h*Q%-sCJ0RWhy>o;aXqiHDom{5gF~d z%u0dDwQeM5P0&0qIBHPKYV^#ZUX7e8sWm_487*tBr8ZpUT}?Y8t;xIW)X}ENG9elY zwh=psOyv-FB3#jfqtO2mCtd~NAws{gmcQo2UoxIpOka{NMVzz#qnY^a(OkOZ#2?LN z`1d~cc*1?|$%*?N=l9W*F0Xe!KlT~n;^Cyd1@!ZMK;q@8;nsCd@5rV5VmO(apk@IZ zN~SPBVQnI{37#qKaSJY%g=8;tVKOSM5&%YA3($hWCiL zFd>PxpfJf>3k(TNC3#iRjERbXWyK}T{7{Q02oL=hR0a#_606|_mBG#hAD;fWCgn?R zC2_6>G*yvaL3#U4Rm&JWyi_eCC~vnd3rf-D9+Z)EntZrPGdynQp;|dYHXL@;;@@AU z8nidTo_Sf8sJ&+Wm3`mm1+GY9ajDz2& zvI9Gqg{Ael7^*zcu0#d5PK4c1vdK;)xbJgL*`Z;Hl!&)qE4=)>Ld&1&hr74^aI+TE zV{&jP;hCe4eslLHcf_ks5(l?q^%2K)d?D@p5|f4_s;2A0@<~orL2wzK>x3ZrnL*;NgOWzrkn4$3kT_YSr#DT00prH<3l$QQa3w0P>KYY* z-7*)tZN+7Pyr`EAM4$@7NF(!%)XMsbWM`&p@Z~t^h^$=!?%PV0pHRfIJD-sdjJu*v z5G!X)9zkVbT9Wo#weA7|-?!dBe{CP9F!4tlLW()6BE;TKj2g5J z6XKA<;HqVlM9=3f)n~dgrHeknL%dl@W39v`JG|neZw1csaL9qeGI6c57TJ~-ym!fD zej?!SSw(9f)%?kvMP}rK_iiP|d&1EVOB`)o;IP|=z`IVL)YbyVCTKe5(Cs01q()TX=m6jg;{tC)xTKaKa%D;PTHOz3s zr`ixpKHTjh+l}ZhlbKA5&Qgm9lW^2g8*$ma*49*1sX?Y0GalkiE3oC=LCWU19#fn; z4Hav80CWxMcSl99^HYc8W;jzeg$<-e8mTQHR4ZLILWrv7_0Uy~6ej@Xkq%Ey`wr9a zJ^%L&EqxEmuW0GF2ut%$4Qo5;%@}TQ{TnUa+L(I4agu50ZPPzM_5`x`5HXo<6qe!bLHtt)VoH^)At4Esztk9SSr#vPlT z&0M;_ zZoKu)z=B;2xzK!dDb$QuM5Aeuz^lDh9(RW-Zf%mZ?0hBVD7;_UoMDeWgpR&yAr!?? zTZ1%q-ALT)STXqRLCP)cWCa03*-<8%PND!&j?1Cw>4>Cd+gC_w>wnAEvOkc9FA1l{ zeQhP(t509k@NhekH{4E1*k5&5MkaFcTJF_7WvTT=Cf;Dej{vd!yG zF-S->o^h^wrYw9vldPdCBSi-xUQvXl5^xM{ftAPeIY+H40ohDVGRjUTQDtQr9zt1a zk#}KQC+s)LO4?*$sYF+08DvODe0Yc4Vu0n>a##_UpTIJB_~_Xe_q0sU{dHq$zA~2K zy&N)@YuS9okK4KGn@N4go$S!!R#N)18p}1?iByfpz|!pGu)Z~5&-P5k@4bIgHh))T z+TEDuhoEwMczKUw3n#N@Bh4Tos5;?rPb9kZ`donQ2$_8)Q# zEdu;(VRy0-VQ~}=?`R7sY^4@}J%}eK+$q)RI;)vRQH_jhu(~|d*t7ghPC{mf^nW1_ zM{CL2->h2j8d^T77Q|}Mzg=kcZ-thR`^1)aV%84fFx4gvU^s^#rowT!3k z8jqo)xGP%zT!&|~b<3N^V-ocLikE)dA)F^>7;CA?bnO+1yIU#!rfGS1e76Df>PQxfTg&2I{aSH!X{0e8 zJnS4VYF4}W+61yryAlUMbGOT0H z>QE{aD0KeZIfte<1|cfZ(l%#ZE~z!r09!=*verqtjmBko~u zDgfhtDB86DCiOu3xtd0b`tz%@#3(w(e& z>NcN=NwL}1EK$gGKM0O|2_}9h< z482@rCk}qp!CN+ckNbE~O@pyQqDY%QS5+6Jv^Hl#p{QkmhdEfOi6DvNPO^Z!bmV5_ zX>fvywnkvzMNtjjQc0_Krg%D>#HG!b0>JOY@PFcb`23Ue;rETlZ9e=LyWroLDF1BA z2akK%qK~Ix8%N>_9-Gol6K-h+PVo#;5X)GjG(hkXi&O@e+QvQLxF>voe*@9N|A9eS z%i?@IHF{ef0rpZtFvn!mPSUEnRYHP?Y^ah*&FCbT8I`TlI4a&`3=Fk?D~6*aHJBy; zkJI)Qr!6|;&pBd)fnnUakIE{-qUDb^-Rh4tAv5g7&YyIB1L{00OgIRWea+zMj3wATa7!*^y z{^ezQ?z7U+Q})nxwk%~6YZ-FS9!ejNR5o8$Ij-1a-^5s>^IYz|Rs3e74uK_2X38m;6prF(>^~Ywg`YetJIA{7 zxhM*9kU`@BE|$m}bv#0rDYy{4)>u>mD3n30R(afYLJ|Amz7yQ#+?*O&Wv8gQ_1?Gy zMZ_b%)E;_OO1jF!m}G65mPIC7m)(v{hfmZ$v4#ar9-Dp65}X89l4^4F($_IB`& ziGGaRcW~(SmFV|er1H4CwvhI550rm?pOE_B_;55MR>voX$})bqMe(vvs~Hjd0MM@O zRN=xrt)0iE&y#We&_a?qVPj~N!UQX+vPKIn%FaZ(2JS&IGV8QKwve?#7*n=jn1FaX z3iup;=-(u2w2kb*QUABq{;tWBkWl=9tU%meYwEF@+^)x;`wH6TY4>n6D%6)5H|24ut+|3h6gaGu{NXTy@LGFGr&Ynx>-wKRE3&C z-O(eXM^51zTx2T@|0qz<sCrJb*A%M?f-AkRv-wCUMs2eJJaEj}XlWIl;-8=sEJ>C@cu)9JF53chxhYha(Z zcegpqWwXd7fu1Wi-*Aw<$2`lr%naYlTDHW>&00ry-tHQScO{x_Ltd=qV6mNCAkmBZ zX~B^uU=vYnQW^2t)V~h1?G@N4it`QNtelj@XmFbvpCx7>z1!|Oh!J;$IzJu8gO>78 z6peN)^qu!juAQ4ysKMVd9I+i*?aMJV6mrZOT%DnaOC+zW5~csB1QTn=C{SET*Ht|s z^%N$hXfC-$b^cmW8kg3Z}YXNFwZx#`usGt{1eC3>h#TOrjILM*6^5CP@ivnel$q z8k5P>iK5gX*P*H;E>ck=lGL-~TgyjTRbvcqUZvFyWBj4{Z{iPq_i)!g*6i>~ zQr{mbnH+ZMkBTt)i3_U$l|#5Mo8AbjdcZuqCa95~(+)6`Xd&M~=UTV83*~gm z-|UE2Et;jc_m=YqZ@Fvo*oQ%$`3A(diHRK!kD%KvtL-lHHHOFH^oko&cKB8dw_lI( z>>OhZ%O6!2gH3 z2X?D#Ye%7EEj1q?f{XZRga_~*nF4QUQLJr@J)m4#mn|Pb3 zmB}?AbGU0>^=~cXsk^dfV3za?UCaNPJkOgv%U^Etym!2Y@WYc3zTat2~&sfV8gz(M*BriJeT8dJb6#(}s?c1w_C{dOTz&Kd7=$nR6 z$xD&1PmQw^&uR_FdqgyHyR3DLEI$-;uRqh9Sfjyc;tv1 zJ$$F|5bM|z%Dp(O>I}qC9}IDX9Q1Gq9T^UXPEQv=(ao)xh@Kb z&e@63Oo>?QAppJO#xelfN&W?aIm>WlM{YZFPxuEzrbd1|zU3?%QKDJ4Kcv(aVZ-v8 zYTzfqCG>zZhTl}*(uoMgu_q^>Xkj28N z2k}(y`546AyyvDzcCvGKK|Geeo&oXat(~U@^{>t9c07jWDLl_EQ?4448SN=;eqQ%d zj9UhatVtgk8%=Y;Vcawsjyzx$l5m^Rg6UPKKg4ztbA=7O8*qR482WMDzGFfuYYg95 zU&^E$?WARe5|&&Yl}#t<5fBVD%Hn#{_mtXbRn};gKO{c%+F8#35NA2B9q#K4?#)@w z_s%lC>zlKjH)pvLHa_w+zJ0vDCOnvXxcl~aY&-Sl-6C?F;2AX7Y?F8z_~IpYBZC^- zux-$beepsqS$SX-e0@Eoi&g!tkNv0t`D#wdK%aumIg3ZQu1LGIW!R>?|?9O;$V z1BWOqxBv^z+D3J;VwASrpWbqoEyK-aOmzP-(|?JXzI+|S|BBB4*H=D=LjG>Mg?E07 z;hQ&|Z&gb$$cr*^op!{PPq?cY8EbKHOerC~J6PmvIP}&Ed?V)>?dznw5s4akLu*Er zjU7x=>N>WIOv%k?cqLWUkH}1iboCvc1_gses}!#QkNw4>rTxD!^f!r_aOyk_@*Sj z+Fk%pnFERobV>0=7}KGori&t*EQF#dPGt*bDXTIo8XG2Yh|{++6#4O#ml@Tetl`U0 zJK|Jr519GL1SEJa7SfT~(ZLU)rYg%i!)<<&kVLAsG8V;%My-`?aV#P`MM=w?0@|V4 zR9SPRgv15TsGRxMEH3X5@bJ3%e`}Us*V5AYvD7^;u>Z&_H3p$Fum?|#No$`yU=G`WfuW%4zfy4NS9GHjYDB{CnJXH z%(*PU+_=)R##!51awW^A)v?9XS~Y6X2N|I^;Z~Mi1Aey$Q>}4|;zUj?qwnpPC~+AN z|5!`^K?<;Ypa4fubE5!9Yo7la1$g-$1=y_ZR)sbc!y}vtq)APglJo-4yW0UkH;u?H&{KllTE-mKa28S&G;$ZJFG>7vU zY`76&zBqnHakeR3n2_L)g~E|WHJS__*otz<4SirD?&8sfjlS4UV~xb~Mo)DkOWYB~ zyNHcS$(sfT!K<9n20%Bs)TW zjqrX|@;5q>(E+@0iHj}9(I}3~RW2Sucug854`tM_9C;itYZaW+VqO{Gn^ZO6b`{y1 z#$d%0FhAs>CF*9e{76r%tue!VvuKIlk~iPvwAot>zd1s;2EXO%pOSRtV=djzn`r;f z=@i_<@YMv}=0%sJHL%RL*5|xeAKFG9ul?}Hd5M%{KGxEon#^^)?Y%Rlf$XLoklX@@HaBdTIo>dKq94lE-uLc-7IkhB%FV^AWCAZSh{lp zJl&jY9OJ>QC#|{|UBKU z1oa;LqQbe|QuLSuVtt&0>#QlkW@E-VExYW*k9E&A=VhLqPUKj_T}xbfl5_SR;^EOO zUz6J2U;xi61K7P_07pJV^p0z@aLw4R3}E|`0h~&GL8Cxo)ea@5z?9UdKj?MPy#60ZjrSG3mJ+lKlAuh?@xRxCfghtwRKkrbUPn z)+3J$!sqC{B3Sq%6pU2aqyy({P@X!p*TE8tgX3Ndy(7bbODTju94^!m!UZ|-!^K}F zb5OcF6s0^gjVTN(iUH@wLQz0~H61&4+>G@A*6EZBW}0H(k=JDdwx4$>=zlJ{;#{1| z10Wtnse+_WQrwJUYmF=Tz}#yrzMC;;3dLVe%5oIcz$XO~(rHa7U?tos_1+3`)N14H zYqMPa$^2Cizi}-eg7}U2Gv8pxpIp{#Z$W&XUoUG;8Rl(S^K#89ox5As?0$r6`76PH zO7x4*^34$cq9KW+&n%z>N8AHGZdY(OIlo5j&YEwYv)x`~?pV7qn_xQ|Dp6uT{tjK;S4d+Z^28O`!_ z+45ftdF%(sW8a26?v862u1TQ1OX@KB8=|7duxgs4X-rt#jwa(=yh%qLbb^oW^Yn3Wrtn#KBpj z?MZ2P)%4h8tW_IL6I^BkuCk^Xl>m9fkyG%#DD0NyOuRz@t^~!_V_SW<$MdoExV-G~ zEVtZpi}&Aa@wnwKw{)9lTyDALs^a11HM!Vkapz?%x!TS8R_}jDV2jr2);p&6x7>Id zPbAal+q}f)?grFJ-TV~^{Hn$>;{rVJSMBvx238UKE~^7M5@MQr;N6!wMs?Pm2gobD&!R9IRh{H)@u8zg=7@WvM!&RWg?12e{-#- z|ALmkwbw|WsBO32V;PO31mr-CB|VFXV+3IaVt{V9qwL@ zarsQkeX^rkJZSVs0#;sS zTtX;+XQN(+K)h|(PpA)lOF=Nw7VV>g;O}mbub;I?mfL)X%pV)%E9Z0G6hZz+-nD4A zs_WX{0YXw9#xIPGF*ZMt|NoXF*+6KTrs?YHy=U*k7^^EyC`npH(v+sA(sSQdmpxAM ze&<+S?0s!=yM@u(58?PwTDTTT)ZOuKf;D;*_>76{;lLjtKN zRd6WvJ2zBKN;1INO!QOY3v;RYDj$qX z*qc@UgU2P@Umcf7>A{m0&tI|Aj~99AvVJ^H1kY)X2khyfCzG_;he3fsVO~3j2~AH> z!I%Pnhl>4qts{O0MY`yNj^d6BhlO? z>8oY$%UCs)W81cKS|J)A>q9vPnb5n#SSsW0Cyj|Hs$-yIbg2I_!WZp$=Lg3*WVqp^ zaJ6$-kov;}o1+v$H|QB>JA%HnU`&<>u!rh`OTW7g*^*6zidK{oJyP2ToZ3N@-$LM{3qVhtqq`0kKG}<{oA|en{N*UGk#2Q zH$ej=3N2x7@F_cIsEvU;`NX>SHj`@ZV|P4Pc9JzQ)@mk;9#w$hGf^}JHp#63Kn*r% zZH_uGn0{itvnHLHB#m`Trf^X+8aI`USfT(IAp}Ah;MY3hZ6&ZgME`g6R+p_jnX;0# zqqE$akDI@=#{yA;IQD*!=e8F2evSQSG`DZj-##mqZx|~Y>o(RK)T7x)ybD(@uT}I) zqf&L}wqpFaQ7lv(x!De*Ohe+h!@T%{mkJl6F9i<^ZCYiNf`ET#>=&vqW zEh!|FsAP$xqH~U8YK_)YMJQOSdCgnaEtn;%{))G}elqlU?=7!C^_K1%-g3F~mdoxf z-7DVG9lfPpJC!cI*z3+8n(s2aI4-k#xXo(`D>VE}K9L+#^&FCXA)Q zKP_BElpTSS1QI2KDRtNg7!ar7{?iDd+M;~_WGBDa*`G$&ia9WNkVWN}LXGefWSp~N zatmIJ3`IBOIQA&}TKUkA6ry}?oX9Wa46!`RFO2m*%mw$wo8v`sDvC>)(~fEc+7jgp zSS?kPWvnc5A9O}UPqUn&s6m$#4oM}>~;iCTVOgX@Dq(NjZ(E*_*e#ByCH;$4!zIr&DWjj0eoJDX0<`6lx=AV>p*va|^(y zuF9;FSV%81R?`@-X0KHT^e^`Bt0^tGJ7a>!0q~Z1ZuweYuy0*mmQF#HH{-M*r*jyv7Zrl(U}O zR3M^U0%`_N3HBLEQfoGa{H-@dVc^0^G@0v_0J)}6nRF7agK*E{w3M+`jKq;h(7eSfM9Z12l~)jT3ox4U(tsi z)`y(DzZ(ooTwTE5|&%_`14cFI$E* zxI1r!^m$SMwBb88&k(m=+cRtm&B2{e#9#8F5!G0sga&{dR1YKyHKkLSsW*w119xlEJNI%j?#pUdxtg&S1qCaTMY` z;934cIo*B+c#;infM;W+MW=X8zHrygNJUudwuj?WUq4jSZ-vhXWXqo(&rI{~G56%L z<0E0$3SO<)yp!@zLp*CwCsZ=+Bt!ZTBJKuEP%_skwbiiT5VA!Hwjija8Zv@j$ciu` zXJok<#_X(eu4bD9V4_4-wZa`LqSgvBOpU+Xm&lgL9^%b&wN>Z-$;EW{pqPH^`+T#Q zeq9aqdMl=He`d4*@o?47d+P}g?t6UlgJSs{Ddy|_?&kU;yaJ@;)|230dL>C&D<-aP zN!na)k$`w?t9x?cic%~pO)UTtssPZClEaOOa%1#7dOdj0IS*yUOW8=2zY>zxa7u<1 zccDd{k+dfzYiZV^?y5ACz^&nJEeyepxnQ*x2XU(x7fjTwrf8PW#fOeGjXkq`T|n^q zcl*WEUkk3)~wEwg+-^l0y9ahJm^?#5}G!#*_|zs40I%L$eG z0BMU+1-GtSb}RT&wF10+(9uQB_Xd=gg0k;Cdk9cJ7u-0Aio5wYf4No zk%NQ_!;O+?k*vop&B!*=ChuO!D{C&0>BPIIlequ2Ov}`SIlvwF6op@pD17-zDgC;Y zGFPh4KLNn3wCq;1}fvi|Sd(R41y7$sJ;wFbue+ z1ocz+P`Xn3$&WG6LRL3V%;Cy$fkh$64c(x7KPor*rPs6TC-1eFz8o#U6f$=wUG!B8 zp9^y4892kT=|ypA3b5-Uzf_l;0{DqyRzk&%%T+rySw?m720jlfOr3EJm~oU>C8{Ad z?uG)t$xOwJG}>f1FG+>yr)h2=wZu_!t(uHdBw1P%&MGhEYpRxQhb#?FzlJ-%Fk6-; zY<@6X=AK6IW%;ZfzC3D&-_MpU+iclZT3^RHwodCF!NHD{;%T{q2>8YlvWQ=Ks^f&U zSmaPE-TV8z&?zs1nG_NwmRnSw2XIWB>-N) z*1Bd!nKxCSB}!<7#mo1Jr8}Ja?wHf14mwxJCf=TN(uL+9i5UpF zy<-&92JEGGGn*aw@UAIzOTp#JsnJg!VNS{FJNdwPGYG%`z*-mb-h(R*RA8SF z^@JK_Xx~cQXAzN8hbh4VW>SE!H%3{NbrflAb^&^)}~5F$zxfrAj&&yX2z!(X@p7YFgqq$V2Y6X87$Rb*N81n#6V6B<_+%E|xWn zFU#Gu#BwMOZGeZPV@U>p^A8r>3QJ5OPD>Zt&dWNLy`;)_;4(H9g;gEop^!8B66_;P zk#kf|-VC#wCqPO|i#*3^vnC#IIPE0v)xq8m-};+KQflVL#a&~N?4F9Y;&7wYeCS-4 zOYJI?)kP!mLC!P-5MIziblJISds6|>0DvM;BCxDU%Vj|p zuB_OgCJG5G@+g~{m`bDinryO?T`C!axJ065(L0B{^Qy0@v0AkV*-L_E2QJdU0|e)F z2!eRXCuJO;xWxG#WTs!DAn;2;oK=`xiuQL$9^Eei@$a|8|F+7@Un!;ETiAmmPLOY` zp@RTc2=5L2aGgW2UcxPiH$&KTV1iD2sJ5eCC4n1hdM%WknlbW`I)|&8x#76oakkjL zX>?rCY#VN33JMV1%s9lWvCxkDP!vY@wyu$-agnt`-4{cemmp6=JDlPX*sMl0j(g5( z)nG~ewH;9esh0mHv%J1$mJeDyKS1Kb?Sch19EN2!3tE)`AVxg47kGu zUAVd79d4LpLP#^)Ty|FXd5>Z-fTt^fX?bfLuc}fsO?FWLufZ%`=d{86vMT^hLk=kz zI74BDrWWFU-btw?%4R6hR1J|amqcloj4)-UikwT*o@2F>yyPt@?>Jax_q;xo=oSB` zG5q@98^c%lvyV$Wa+be&gwMYD40;{vL&LNqdV9A}5BD`Iq-{DrhMtX)yU{A?4a2sS z14t9Qr|W*_83O$b=vzu_;%r(RPD|``oC8vje&W42wQGaODLJ>`K-Ej+Ax=9AW=Xpr z4wr2M;_mAK@xN3bdUaT0xuwO+cjm!Y`p|C5%cEh5U*3B1%_~1V-S1|J0)mhk-p=0b z(I0Gc+Zv@O6^9^k*O_y|sYpO+g)!6^6Q+t`u`;Kqg4rnWykL8iH5J%aT@w7!tfqB! zRseZO*=7wvY3k0rGA_|@63vp;e`1!`4`ylqjmvlr&6oFPX@AcwU%6&DG=)AKcLk_O ztyFX38#y1f;=o3GZC$d-X~a!B3N_+XEkqpY5tvh)oRe?^&U4y3(tsI?Defsln1ikF zw1`|YE_7e@aA&BR>|FO)DQX~mtDI@jzE6c+9w__EQSo0~KI1ze{?L6XGV3EYpY>u9&Fn8s#cS1X@T<+NOye z7#U!7Mf(`BO_~A^D8I@i7+;-bHGyxMw#Hp2xHw8SL}z7*ElC0Z=_TQUmf|R`;6IrV zx63VvziaYDKJfov5Kk%OzV*cJX1OFTqf_sl=m9<)ywZ*gC^EBLt7LR-1;<O<`POk4PFjoLV=M|n za*}bam{gEe)}lqi5Mc(_JZ6^~b+54RL&zB-b`v$)Ag82~!gZyt#B2Pax~rpEKBu+W z*F}K8p5n2I$hHyFR~PlN2=K$s&Gb`oACNN?e^6a&-FOPlk759lTzA(bobR+ zhLw!&k^eaQWSGjK`K5&rCH!7W0sr7HYdyxv`03ah*=W_=nIZ1BTSYa{zfF$&O@L#F zJDueWn3mDg2$vDwdOw$w9!6lz-xE7GhaZKts9g*YVBCW&Y zh^{m9=j_JV!_Fu*DKl7&P-(+Be@BApSd)}{e!{B{{NOwY|z*6R@qM@q1XFb&( zt*&ca>Im+9K#7B?0*4G1^sKTL1y`q+jAg?bgylz(m!HX{-~Iu)^xs+HxqZl`(+Bj0 zuC{wf_oE}=IvwAT#88Clfuj(=nDtJj{1mV=Ls9pzBwmf1dVKsC02Zb14bF-Kgwb#= zK5oXn<34^Y=E_XhAcKV1!5D7pAQgDz1sjws;6YjN-j`meVUTuW#x%J?nbnptj|1XG z)#jH=YrtMIm2(IpmBv}gO4^L&9EU9GJ_kr^6mU~n-2lRAZ`rxYbIP&5HpL^_8erKR zLQB8i3D25*cw(ny-*yBgSo)pt-1{^(7al7vt2eBh-0no2 z-q$wrxSLB)La93ucbkc%j|08)*eA5Z@0QG^d(U_tVL5M5_>7PEZQ2_f*Eirj-Y`G; zDjHgV8&>;DAD@`-TckEhLXT!OOM)Z!cHU;n`84@`&!Z1+oWbXVZ5Ja0l2SE8s2PNT z;MpgYmf|AnM{D)s`wD)jozjq`qP#hZY+<8@vbX_Kqo| z*3k89p{3{%mi%`m)4$tndHX3I?w>gE+xj#;v=8Ebmxr&n!{WR<4_`kf)8Ts^)F}!0 z>cxdLtnH}nhn(_)^+weH#U9DXfArYv`AV_lvigHV4-+X?1A50UD5a=)O=}?G)X8hy z_c#%-RfjVeC=as$n_8uh^WU>a2DEhW%+mU`Rr6Z(#;m^eT=Z|nwSyobTr2t37;w5M zrqP?x)G`Bi-dlm%Ej(A+v2YD(ucX;OKi#BVRZ4W@R_PpWEz>s*uUb2>5k3_utv`=Fz-+i}F z!~N;l(!UT}ro2vyEmLFfy7}~#p!a2;hX3xw#EVDNr2KGpNurhyXHVmBU8rVFPx#PX z1Dau+*MXDe9DqdOLZ`KKz{STNi-stZ72JsghA?B5<-+<>bwddx$K?$#E+Uz?K~{a` zmayc2!m7-853JfuK-XE_!|_(A;_Z!Ee9svKk7r=qXPz~dHLNxk^XW_oX)3EO+C=&E znh_7rc-a}WzNn%8QjJGSbmIL_l^zeUyuIkeZ$DzmX#(<-h zTOnMVEyYgt9x;I_9(O}M1I@9tM9&x@I{acL{vEh<@M!RLAjAZ6gPlV-6T-PRsPV6I zT;Y7Vyf!1=bO1{rr-aMryNU^mfE~(G@N;k#F1F&)V z$-Ds*o6152>k_8En=qk?RqFIZ3tQA?4_JYMuUDUb{ESxuBZI$e>mkN;qYGXwzCabi z)=WVe>hP>MDWtk9YtBrmTu2fiYNys;1$G~|K8Ct_c4S%AJWZ3E;Y*-oN&~N<4fj*1 zF(}Z&I@*DzDq$*gj718)zZ{?^bmEXhnSrEgu>BdQV%XT+v@nct!PTt6EV7Nq2(y3;HZHg zm*dt!hQJyZUxHE6V*pr`emsryGOBPA@*Fr#(Pa9IQ7)=f=R>>%6Gynk%HrO_16- z3z!>7FDUPUhWAC^!>hH0Iw^xfY~0qC)|^}*e$28KTRSGxInx>7-MBojYQ=@KUZ2mv zaT?U}$1g|*_>~smT6EZ_QMdKar-#1ITCNX~WeP6cUlCkJr~4#v>HH(-iEw+LxIA#4 zTS^kG>q9#Iwkf9nkz-2%eW@kj_xJ#JL`95m-9uDG1T+n_{2Ttq$;N2{ zhb-wS0I?$KZ#{*tf%?sH_h`_};&PL-woVuzJo7v;C1r(u9D<#NLTRl*W|D>}EhUiJ zmtfg9yaHH?yJGqWQ~6&yE#ZIrw1hiOJjNH>1O)ro3=}5{@z+0+G;JDAiD4;l+;eOFxDHDXz046g`2yP}FkR06KoQYmL%p#Gf zTih@4Qe@cz$wye$ADs9tiZp*{)Syz-h2WN02F3MjjWnDK} zU^RJPDN$uON2VDL<${gG_Dj)bIqwxdD+h;SdDWys2%v-OZ)KTEl>wjY}APP^<{2^1s*q zbH+q-#>8cH0lI_zm@ietn;zTR>h2pA@raFQl*ey=JZAP%xR`$TTQ^5am;3lDCy-Oy zrX$MZ4uso1H2m&kUh$_=Hs`KQy`6iXw!Had3ezUD?e`dCOInV5Ph0xbrI%8eertxi z#UNo#0)p{{Zt>!{Um~V`P#g{SnBXtJ9Mx2k@=z%8aRur(Z%{@Nl+NC6M2- z1d>h17_N(hNBFkCo=gMGU6r~N3fD1Dg(w!!+$1&`|j@R6-7b#;IaG zLi3f#lJ^2UIIHWg0?XUyf#ognoh`8R4}oQzepubU^kgM=PezU0{(W5HPc1z;#FfPS zk3wyGn&GyaNq5`KUHfg*EG1DZe4C_)Xr~^^|AU>olH{dW#(8XO>_-owk&SJ+#ucIh<@W^!JwZMEc#|U@X6%B0U((<=CZhkSnm@mT6^fuoGC!*#+Bx{hLSn%)Iq`c8b!R zKwmWJ79GqY{8!Z-_WS^{t(|7Hp}6yYQmk_ZU<|Han(&I;Dr#yI)cEy`_;VbuKTM zDZ)BVUQ$6Emx!M`;NRJ$JcFC(`T6|XfH>xT~Bb=#M`-Y=)^whL;hs?hC5axQ5q*XmG$Bki37?{^LBh+y;q zrBBmQ`VO0aX_4}>mgN|h-pte0_rOl5e2#X|GWer&xJJdz*jj|d8Xfj9*(ZN^J$KWHib=o{Z*vWxlwNq+9^j34*xD;}uDQ;I<9XRL-9cQb17iw%(K+UsN}SSd zQTZ25Bn{_Ya9htsyjBnIBtswG{JsHkpW1Sc*7DteI02Z7)Ra4??DXS+_>Ii#9$Mah zjqy+<8$-+6mgwI?%f|unEtBr<@n)=kuUl-nb!|4KAuQ8u@TsO7OJgQ+ zov+uj>#p@U3wI?YjNVSZoe^R^5FY8dTsk|nmN_wn(^U*(*It*#N>{x#O(t@YfpN-|i!i$@s0?sN=gXjo8skF5D*#CZ_dN z5i8nDG?p|+hErmsmHKeS-GO6PFh-8s?Coh=atpEG+~Xuf7-GtCb^|p6ukN8aB*azZ zWVK6!iS+rN!3^HFZPDs>ZsjD`lROn&p$wd?+g8a%cbRIqsw<|sFc~j#rM;-Y8n$Xc ztqwNenjggq*$IH6b3r>?Ar4oZ!8r0xTD&DlnYVfBXH%NN!x^Z#1{(?N9NUFoR7{sr zASzq=zf^YIZ22#h9jPAm#Y)^?KIX^Qef$aGJ`oX@PK9>dLIc|F3?GSk@w4Zc3Qrid z8vE2|>Ps>PB8Y|N6-k;ps;5s@qo6;jV=W_ie5sb=4fjiG9f10NUGeGW^XN_L;XG8&aVJLKQP(%oT+ zcM;u)-Z4h4J1lR10W8<`+3vF2$Mn!+(vr}6-w}1&VEG)6yCT*5ryr7(sa4&EWJ>+r z$){I&BsMT3l3u?LK}r4&b@zv|;`dW7HOGr;HIjB z;4nCFxz-A$!4E5lDaOfoFZ!kLvG_Qgit2LF%1k&{0eGBQmq}bcs%Z9CcJx zowdTq{M^uP@$ABS+y)6gzJF;M5AT`|VA=ob3{UF6`S*{OrGJcXjh6jxGx`p>Nt%D% zH=I4Y@=)Q~Qc>%DQ8PrVL6Y%|JDY2TN~$R7A5L1M)T*xV126;pEao8xW3Uw+I1x6$ zO}Zi$#970z7!J{=FjnhQ*-qyr70yvg<8p2;uSAv|7d@a-@~=?2KBDqTa>yS#+TtL@ zt{&)a_sDW}55RQM&br4K@|*p??g=p6UeKZ1Q>5Xy2g2?4>}2#1k#JMbUXs&rYZUyr z#Rj~aOT8y6U5#%aQ0bGhRXEx~_~lJ; z6|`d31Y-xFOhRaq_g|Xvx=5|1mmRtAmGya}c;3n^W45ynXf`C|s?B6b$TUp)f5ldw}R9_aW%XZr&BqW_Gl8$tA^bfbn@EPA&<#nlqZ>(~@v&wm6mGODYYo4vr10y{3 z$|~P2xA*HJ{H+U^2AD;taOx2sS<;FaMH5mfLeDjl zbsHuc)qQ^UHuHUUaDAtsLvR8V13nO9c+*i{V<{=mYo36&L>QeQdABP&MMRqBr<$=O z#|fTu(H$bCmxQ2MZYIm@Gu{arS>B<%=!OS86qO#Yk0gx+@Az)`9Otuaz&&v^G0Z>y zEZkYRYDNqSrB%|N8&l~t zsY&mQWGIHEu-9!QEfGOsO3+k2YPpqlC#(n*rivxhL? zY8~SRJS2(=JZ@5B=Q}-D9CE{RjjVJEi2<)W$@DRj1}oqWt4aOUz~k#6?)}En_4ry3 z>#HFC6%0R^TJCABF4p(kTC0C8wfs7feC3h1kM9sI-Lg*a#{Id!;j_!A*)ea{0B1m$ zzgXN};d|!^*O+OxBD@GonMG1}TtJ3e!l4v3IMySJ62tkKYIbPLV}%MYH6dTM!#5R{ zztRr3zugYM?zO{X6rV%rwo4^8QiFEe;dkD09W4tbqPR})&U_wCDX2|%L+FtE5;s03 zkp1H+KtT~`p3DRhG}mgHbFU7Zo7^gtW5EieQ*K&D9fxsn!=xP(qhqeMeCVff9VYj0 zH+CMN`)a#u1eaMaQEkIC5-!hLmFFF<#OvWIJ$Or+b{(U#0JMWTg{tCZQ4;~dJF6hC zRHdD=Pe@y{jwcCZj69_&)*?}epsBc$Nzyb)*HbJHCFiprZNwB5d@4cCM&j?I6FnBh z8A6^f7MK0IDQ)j)={w%?2Rc1(j`iIXpybixCEi;<8*Y`=K_;f-h>|df%Ta!cJpb(3 zq&w|=&2o(Y%c?GDqe8O>m+@%06t_+D$!({mEbG8Tg%UVVQ3=7ds{|>z(N&F8XiDIE z3dkP8FwX>hBZT)7ESD9nltob%5?^b|LlVF(Qrhaxc=-R!@{n21+uZWOP~v_5!iR2d z2J!P(13GujopD<4d4D*#OY6GPER5dJB=S)gTRfvD2r*@2G-WQ+ut?I@R4gn|K& zIwev%fa513!JFc|8Q5f5GL+cBfi=un4~>U+1xf(d?fa!C+aSIm@pU}h-iqm=AQX`5 zH8zpsFhq!;K6ms@?_gs=Y9oT(1;N{;k$D`6Utd||E-(G+-(N@RnV4@{yXl9A22aQ_ zgWZO<&%CyMu7Qbky=PiZ?}atS^^ez2i;18I%;>jnf^FPkr0zz|CFjO^Y4jdTOmk;q zm7U6UXOweIU~>?rvG6pSu|c0{@Vd1{PMg-FHd0spX^(5|9N5u7kHPO7#oNZNt9N?dHlxJe+cBeM-z9gV0C zk%wBOrPpou>t)M%j)wea5YHbL4-A)jXgtm@8jp4(FyueL9pYKvIyN5X2gGx5FnqeB zkiRm_?eV_OWcMEqWOfBsI^tqSECe;U}@@U_Z z+P3T=Uq%lx+-I$U)%o+}p{1IxuW!ghx0=x-c_<{F>ulM)RMU@G#qS+2t}xlB)BA$1 z{)ET-8)p18Pbo2O;<$EMq0@7Ie;%%uFv6%>ab_TRchiiE(JBF;z6HZl47{TnX`0|| zNE^ZGxG!BMWl<%B6yP@#Y?EsR@I0+i-38gfL6Go>dSFQ_55(EC^3eZV#AA;mo_VjD zKF{xf_~9mYc(e_Fybse35yyvh`hJS+Vx7H=v1a72&@K0Hu}=rM9KK#dCI&NFCp9*D z20zuy?P!CKg#5DCz3dCxCA6nXH^_v;vJ(VlEnN#B2X|F`@(Ii7;0Fmdz6pV}R4}Op zj@q`U+2-K+t_O^hkTOt(P+7ggIkP@VYF0zS+R{^c%q(k^@vm9+JES&yoYeOBbIX;e zp|{qzpIhn}#6u(f8qv+dbH7#7=euh9Uo8k7%@S7az2PUKI#=82h&lmwit`&@M%Tt(wNS^1N>yzHYSP!#%x`xqIYxM^2BA`x5(z z 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

4^_5 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�{mpQsr1Us*0|0nxTTF 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 literal 0 HcmV?d00001 diff --git a/DemoData/zr5156_2V3V4_R2.fastq.gz b/DemoData/zr5156_2V3V4_R2.fastq.gz new file mode 100644 index 0000000000000000000000000000000000000000..51ec621e6656f21489415bdc438d72700645482d GIT binary patch literal 179465 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

3{tR$N5YfLsj!0lo2VYAzRF^_!91k4ZA@F+gq zU+QKXk9@V`u*=gNvdccQqNtnH)!?qnho9OPGm=@D( z9#2WXTIRC&%K|IeJlr~GB8hzD(=@mtDv{HEGF{cA9LJ7y;Oq5qWU6}tMG}WFC zF_&O{n_EA3PE7PxLu}OLNX)r?sL9H_hqxc5!txs!tP>yo*vM&~M4M$fd;&xZ+3iYF za&rw!86(CqGi5kuI!Vg{elS|5C61Twe2tT!RC*}{;M$}y+%U}CBE1F>NqWWMr`T(b z8QB6HY=yF+7;+JUNVW_(0Cp*ol%;?o6lQLN9#h@5NNzj>5(uqJ1PKlKoVdLo+3hcZ z1Zy`a8uLegTnuDa*NyR^-5Mi<8GdezoR`MPnB@D^7#R=jb^%$qrhMP!`)hdNISzY0 zo{JuI*|rgV`yXtIaTp4S`6Z(;f6wNikvI{1HB)O<5N`ef8$dV>3VO*W+ zHxpcN#j5f^e`#mBhd9B$Cn?wsCw$`9+&|-lNVVFr8bc-aA;9z}fx`U}8^+JQ0}A## zpb$-U%Pzz}%5xHI84(f^M1BpmG~Yz)Ub(X4!z%a5ggG)_*2j@L@cgD-q9TkR5#zYk z;aoey<5|WmvK@C;9rFwf)tGWg

Fv6Uk=M(7A=?`VEKJ` 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%0D`ar_uU5xMiC4? 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 z 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 literal 0 HcmV?d00001 diff --git a/Images/qp-qiime2/qp-qiime2.dockerfile b/Images/qp-qiime2/qp-qiime2.dockerfile new file mode 100644 index 0000000..fcce068 --- /dev/null +++ b/Images/qp-qiime2/qp-qiime2.dockerfile @@ -0,0 +1,87 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential \ + zip + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + +# Download qiime2 yaml +RUN wget --quiet https://data.qiime2.org/distro/core/qiime2-2023.5-py38-linux-conda.yml + +# Create conda env +RUN conda env create --name qiime2 -y --file qiime2-2023.5-py38-linux-conda.yml +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/qiime2", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN pip install https://github.com/biocore/q2-mislabeled/archive/refs/heads/main.zip +RUN pip install q2-umap q2-greengenes2 +RUN git clone https://github.com/qiita-spots/qp-qiime2.git +WORKDIR qp-qiime2 +RUN pip install -e . +RUN pip install --upgrade certifi +RUN pip install pip-system-certs + +# configuring the databases available for QIIME 2 +RUN mkdir /databases +RUN wget --quiet -O "/databases/gg-13-8-99-515-806-nb-classifier.qza" "https://data.qiime2.org/2021.4/common/gg-13-8-99-515-806-nb-classifier.qza" +RUN export QP_QIIME2_DBS=/databases + +# configuring the filtering QZAs available for QIIME 2 +RUN mkdir /filtering +RUN wget -O /filtering/bloom-analyses.zip https://github.com/knightlab-analyses/bloom-analyses/archive/refs/heads/master.zip +RUN unzip -j /filtering/bloom-analyses.zip bloom-analyses-master/data/qiime2-artifacts-for-qiita/*.qza -d /filtering/ +RUN export QP_QIIME2_FILTER_QZA=/filtering/ + +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qp-qiime2.sh . +RUN chmod 755 start_qp-qiime2.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN chmod u+x /qp-qiime2/scripts/configure_qiime2 /qp-qiime2/scripts/start_qiime2 +ENV QP_QIIME2_DBS=/databases +ENV QP_QIIME2_FILTER_QZA=/filtering/ +RUN /qp-qiime2/scripts/configure_qiime2 --env-script 'true' --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-qiime2/" /unshared_plugins/*.conf + +CMD ["./start_qp-qiime2.sh"] diff --git a/Images/qp-qiime2/start_qp-qiime2.sh b/Images/qp-qiime2/start_qp-qiime2.sh new file mode 100644 index 0000000..72337ab --- /dev/null +++ b/Images/qp-qiime2/start_qp-qiime2.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qp-qiime2 + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +cd / && python trigger.py qiime2 start_qiime2 /qp-qiime2 + +tail -f /dev/null diff --git a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile new file mode 100644 index 0000000..ab32e36 --- /dev/null +++ b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile @@ -0,0 +1,66 @@ +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget \ + libpq-dev \ + python3-dev \ + gcc \ + build-essential + +# install miniforge3 for "conda" +# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + +# Create conda env +RUN conda create --name qtp-job-output-folder -y python=3.6 pip==9.0.3 +# Make RUN commands use the new environment: +# append --format docker to the build command, see https://github.com/containers/podman/issues/8477 +SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-job-output-folder", "/bin/bash", "-c"] + +RUN pip install -U pip +RUN git clone https://github.com/qiita-spots/qtp-job-output-folder.git +WORKDIR qtp-job-output-folder +RUN pip install -e . +RUN pip install --upgrade certifi +RUN pip install pip-system-certs + +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg + +WORKDIR / + +COPY start_qtp-job-output-folder.sh . +RUN chmod 755 start_qtp-job-output-folder.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +RUN chmod u+x /qtp-job-output-folder/scripts/configure_qtp_job_output_folder /qtp-job-output-folder/scripts/start_qtp_job_output_folder +RUN /qtp-job-output-folder/scripts/configure_qtp_job_output_folder --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-job-output-folder/" /unshared_plugins/*.conf + +CMD ["./start_qtp-job-output-folder.sh"] diff --git a/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh b/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh new file mode 100644 index 0000000..8863b74 --- /dev/null +++ b/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qtp-sequencing + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +cd / && python trigger.py qtp-job-output-folder start_qtp_job_output_folder /qtp-job-output-folder + +tail -f /dev/null diff --git a/Makefile b/Makefile index 5039549..d2fa0b2 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,18 @@ plugin: Images/qtp-biom/trigger.py Certificates/ $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` +.built_image_qp-qiime2: Images/qp-qiime2/qp-qiime2.dockerfile Images/qp-qiime2/start_qp-qiime2.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` + +.built_image_qtp-job-output-folder: Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile Images/qtp-job-output-folder/start_qtp-job-output-folder.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` + .built_image_nginx: Images/nginx/nginx.dockerfile Images/nginx/start_nginx.sh Images/nginx/nginx_qiita.conf cd Images/nginx && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-nginx_qiita mkdir -p ./logs @@ -85,7 +97,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur +images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur .built_image_qp-qiime2 .built_image_qp-qiime2 .built_image_qtp-job-output-folder environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env diff --git a/compose.yaml b/compose.yaml index 55ed0a0..f0bf495 100644 --- a/compose.yaml +++ b/compose.yaml @@ -282,6 +282,46 @@ services: networks: - qiita-net + qp-qiime2: + image: local-qp-qiime2:latest + command: ['./start_qp-qiime2.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + + qtp-job-output-folder: + image: local-qtp-job-output-folder:latest + command: ['./start_qtp-job-output-folder.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -303,9 +343,11 @@ services: - qtp-visualization - qtp-diversity - qp-deblur + - qp-qiime2 + - qtp-job-output-folder - qiita-db # as values in qiita DB might be updated environment: - - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:" + - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" command: ['/startup_plugin_collector.sh'] networks: From f5f2ced758d2c6241d85360b7ec1f812ef9fe21d Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 6 Mar 2025 17:28:34 +0100 Subject: [PATCH 075/287] a novel mechanism to create mountpoint sub-directories in qiita's BASE_DIR --- Images/nginx/nginx_qiita.conf | 4 +- .../startup_plugin_collector.sh | 2 + Images/qiita/config_portal.cfg | 43 +++++++++ Images/qiita/config_qiita_oidc.cfg | 8 +- Images/qiita/qiita.dockerfile | 6 +- Images/qiita/start_qiita-initDB.sh | 10 ++ Images/qiita/start_qiita.sh | 8 +- Makefile | 2 +- compose.yaml | 95 +++++++++++-------- 9 files changed, 127 insertions(+), 51 deletions(-) create mode 100644 Images/qiita/config_portal.cfg create mode 100644 Images/qiita/start_qiita-initDB.sh diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf index cf8ba9d..ae2f2e0 100644 --- a/Images/nginx/nginx_qiita.conf +++ b/Images/nginx/nginx_qiita.conf @@ -57,7 +57,7 @@ http { # CHANGE ME: This should match the WORKING_DIR in your qiita # config. E.g., - alias /qiita/qiita_db/support_files/test_data/working_dir/; + alias /qiita_data/working_dir/; } # protected location @@ -66,7 +66,7 @@ http { # CHANGE ME: This should match the BASE_DATA_DIR in your qiita # config. E.g., - alias /qiita/qiita_db/support_files/test_data/; + alias /qiita_data/; } # enables communiction through websockets. diff --git a/Images/plugin_collector/startup_plugin_collector.sh b/Images/plugin_collector/startup_plugin_collector.sh index 6dd2ad1..3996854 100644 --- a/Images/plugin_collector/startup_plugin_collector.sh +++ b/Images/plugin_collector/startup_plugin_collector.sh @@ -8,5 +8,7 @@ done # it seems to be necessary to give the plugin container some lead time # TODO: this might be more appropriately be addressed with healthchecks in the compose file sleep 3 +# create WORKING_DIR, UPLOAD_DATA_DIR and BASE_DATA_DIR in shared volume +mkdir -p /qiita_data/working_dir/ /qiita_data/uploads/ python3 /collect_configs.py python3 /fix_test_db.py diff --git a/Images/qiita/config_portal.cfg b/Images/qiita/config_portal.cfg new file mode 100644 index 0000000..a9dad14 --- /dev/null +++ b/Images/qiita/config_portal.cfg @@ -0,0 +1,43 @@ +# ---------- Base information for the website ---------- +[sitebase] +# Logo should be 100px by 40px +LOGO = /static/img/logo-clear.png +# Full path to portal custom CSS styling file +CSS_FP = +TITLE = Qiita + +# ---------- Welcome text on index page ---------- +[index] +HEADER = Qiita Spots Patterns +TEXT =

+ Qiita (canonically pronounced cheetah) is an entirely + open-source microbial study management platform. It allows + users to keep track of multiple studies with multiple ‘omics data. + Additionally, Qiita is capable of supporting multiple analytical pipelines + through a 3rd-party plugin system, allowing the user to have a single entry + point for all of their analyses. +

+

+ Qiita provides database and compute resources to the global community, + alleviating the technical burdens that are typically limiting for + researchers studying microbial ecology (e.g. familiarity with the command + line or access to compute power). +

+

+ Qiita’s platform allows for quick reanalysis of the datasets that have been + deposited using the latest analytical technologies. This means that Qiita’s + internal datasets are living data that is periodically re-annotated + according to current best practices. +

+

+ For more information about how to use Qiita, visit the + documentation. +

+

+ Note that you should be logged into the system to access any studies and + files available. +

+ +# ---------- Study listing page ---------- +[study_list] +EXAMPLE_SEARCH = env_matter = soil diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index 68ddda5..bc1511e 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -26,16 +26,16 @@ REQUIRE_APPROVAL = True BASE_URL = https://qiita-container-anna-nginx-1:8383 # Download path files -UPLOAD_DATA_DIR = /qiita/qiita_db/support_files/test_data/uploads/ +UPLOAD_DATA_DIR = /qiita_data/uploads/ # Working directory path -WORKING_DIR = /qiita/qiita_db/support_files/test_data/working_dir/ +WORKING_DIR = /qiita_data/working_dir/ # Maximum upload size (in Gb) MAX_UPLOAD_SIZE = 100 # Path to the base directory where the data files are going to be stored -BASE_DATA_DIR = /qiita/qiita_db/support_files/test_data/ +BASE_DATA_DIR = /qiita_data/ # Valid upload extension, comma separated. Empty for no uploads VALID_UPLOAD_EXTENSION = fastq,fastq.gz,txt,tsv,sff,fna,qual @@ -181,7 +181,7 @@ PORTAL = QIITA PORTAL_DIR = # Full path to portal styling config file -PORTAL_FP = +PORTAL_FP = /qiita_configurations/config_portal.cfg # The center latitude of the world map, shown on the Stats map. # Defaults to 40.01027 (Boulder, CO, USA) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index 18a4d32..22287a3 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -62,7 +62,8 @@ RUN pip install -e qiita --no-binary redbiom # Copy Bash Script to run Qiita to the container. start_qiita differentiates between one "master" and multiple workers COPY start_qiita.sh . -RUN chmod 755 start_qiita.sh +COPY start_qiita-initDB.sh . +RUN chmod 755 start_qiita.sh start_qiita-initDB.sh RUN apt-get install -y curl COPY start_plugin.py /start_plugin.py @@ -71,4 +72,7 @@ RUN chmod a+x /start_plugin.py # hide certificate and server configuration copy from source code RUN rm -rf /qiita/qiita_core/support_files +# hide default configurations from github sources +RUN rm -f /qiita/qiita_pet/nginx_example.conf /qiita/qiita_pet/supervisor_example.conf /qiita/qiita_pet/support_files/config_portal.cfg + # CMD ["conda", "run", "-n", "qiita"] diff --git a/Images/qiita/start_qiita-initDB.sh b/Images/qiita/start_qiita-initDB.sh new file mode 100644 index 0000000..62aeaf2 --- /dev/null +++ b/Images/qiita/start_qiita-initDB.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +CONDA_DIR=/opt/conda +ENV_NAME=qiita +#PORT=21174 + +# We execute qiita-env make every time. We expect that it will fail always but the very first time, as the qiita DB should exist from then on +source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true +# To avoid confusing the user, STDERR is written into a file and only reported if it does not contain the text that we expect to see if it just reports the existing DB +grep 'already present on the system. You can drop it by running' .env-make.err > /dev/null || cat .env-make.err diff --git a/Images/qiita/start_qiita.sh b/Images/qiita/start_qiita.sh index 2a65826..4b8ef08 100644 --- a/Images/qiita/start_qiita.sh +++ b/Images/qiita/start_qiita.sh @@ -10,10 +10,10 @@ if [ -n "${MASTER}" ] && [ ! -d /qiita/qiita_db/__pycache__ ]; then source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; pip install -e . --no-binary redbiom; fi -# We execute qiita-env make every time. We expect that it will fail always but the very first time, as the qiita DB should exist from then on -source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true -# To avoid confusing the user, STDERR is written into a file and only reported if it does not contain the text that we expect to see if it just reports the existing DB -grep 'already present on the system. You can drop it by running' .env-make.err > /dev/null || cat .env-make.err +# # We execute qiita-env make every time. We expect that it will fail always but the very first time, as the qiita DB should exist from then on +# source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true +# # To avoid confusing the user, STDERR is written into a file and only reported if it does not contain the text that we expect to see if it just reports the existing DB +# grep 'already present on the system. You can drop it by running' .env-make.err > /dev/null || cat .env-make.err # This was commented out bc it stopped working anymore and i was focusing on fixing something else, if you create the database for the first # time you will have to pick the appropriate options. diff --git a/Makefile b/Makefile index d2fa0b2..d6b0bd5 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ chmod a+rw ./logs/nginx_access.log ./logs/nginx_error.log touch .built_image_nginx -.built_image_qiita: Images/qiita/qiita.dockerfile Images/qiita/config_qiita_oidc.cfg Images/qiita/start_qiita.sh Images/qiita/supervisor_foreground.conf Images/qiita/start_plugin.py +.built_image_qiita: Images/qiita/qiita.dockerfile Images/qiita/config_qiita_oidc.cfg Images/qiita/start_qiita.sh Images/qiita/start_qiita-initDB.sh Images/qiita/supervisor_foreground.conf Images/qiita/start_plugin.py Images/qiita/config_portal.cfg test -d src/qiita || git clone -b auth_oidc https://github.com/jlab/qiita.git src/qiita # remove configuration and certificate files from upstream qiita repo rm -rf src/qiita/qiita_core/support_files diff --git a/compose.yaml b/compose.yaml index f0bf495..2d41b80 100644 --- a/compose.yaml +++ b/compose.yaml @@ -18,6 +18,26 @@ services: ports: - "15432:5432" + qiita-initialize-db: + image: local-qiita:latest + command: ['/start_qiita-initDB.sh'] + depends_on: + - qiita-db + env_file: + - './environments/qiita.env' + environment: + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + volumes: + - ./src/qiita:/qiita:U + - qiita-data:/qiita_data + - server-plugin-configs:/qiita_plugins + - ./logs:/logs + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r + networks: + - qiita-net + qiita: image: local-qiita:latest build: # image wird hier direkt gebaut @@ -42,10 +62,11 @@ services: - MASTER=--master - QIITA_CLIENT_DEBUG_LEVEL=DEBUG volumes: - #- qiita-data:/qiita + - qiita-data:/qiita_data - ./src/qiita:/qiita:U - ./logs:/logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins - server-certificates:/qiita_certificates # - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh @@ -69,8 +90,10 @@ services: # - 127.0.0.1:8383:8383 #damit bur ich dran komme restart: no depends_on: - - redis - - plugin-collector + redis: + condition: service_started + plugin-collector: + condition: service_completed_successfully env_file: - './environments/qiita.env' environment: @@ -80,9 +103,10 @@ services: - MASTER= - QIITA_CLIENT_DEBUG_LEVEL=DEBUG volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./logs:/logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins - server-certificates:/qiita_certificates # - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh @@ -153,7 +177,7 @@ services: depends_on: - qiita volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data #- ./logs/nginx_access.log:/logs/nginx_access.log #- ./logs/nginx_error.log:/logs/nginx_error.log - ./logs:/logs @@ -170,15 +194,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -190,15 +212,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -210,15 +230,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -230,15 +248,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -250,15 +266,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -270,15 +284,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -290,15 +302,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -310,15 +320,13 @@ services: # tty: true restart: no volumes: - - qiita-data:/qiita + - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita networks: - qiita-net @@ -332,20 +340,29 @@ services: volumes: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - server-plugin-configs:/qiita_plugins - - qiita-data:/qiita + - qiita-data:/qiita_data - server-certificates:/qiita_certificates #- /Daten/Git/jlab/qiita-container-anna/Images/plugin_collector/collect_configs.py:/collect.py #- /Daten/Git/jlab/qiita-container-anna/Images/plugin_collector/fix_test_db.py:/fix_test_db.py depends_on: - - qtp-biom # one of the plugins - - qtp-sequencing - - qp-target-gene - - qtp-visualization - - qtp-diversity - - qp-deblur - - qp-qiime2 - - qtp-job-output-folder - - qiita-db # as values in qiita DB might be updated + qiita-initialize-db: + condition: service_completed_successfully + qtp-biom: # one of the plugins + condition: service_started + qtp-sequencing: + condition: service_started + qp-target-gene: + condition: service_started + qtp-visualization: + condition: service_started + qtp-diversity: + condition: service_started + qp-deblur: + condition: service_started + qp-qiime2: + condition: service_started + qtp-job-output-folder: + condition: service_started environment: - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" command: ['/startup_plugin_collector.sh'] From 78cd4005824b98ac89f9d7b60412572731345dc9 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Mar 2025 08:31:42 +0100 Subject: [PATCH 076/287] also fix the conda activation command for qiita's private plugins --- Images/plugin_collector/fix_test_db.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Images/plugin_collector/fix_test_db.py b/Images/plugin_collector/fix_test_db.py index 49084cd..7865708 100644 --- a/Images/plugin_collector/fix_test_db.py +++ b/Images/plugin_collector/fix_test_db.py @@ -9,14 +9,19 @@ is_test = qiita_config['main']['TEST_ENVIRONMENT'].upper() == 'TRUE' print("qiita is in %s mode." % ('TEST' if is_test else 'PRODUCTIVE')) -if is_test: - conn = psycopg2.connect(database=qiita_config['postgres']['DATABASE'], - host=qiita_config['postgres']['HOST'], - user=qiita_config['postgres']['ADMIN_USER'], - password=qiita_config['postgres']['ADMIN_PASSWORD'], - port=qiita_config['postgres']['PORT']) - cursor = conn.cursor() +conn = psycopg2.connect(database=qiita_config['postgres']['DATABASE'], + host=qiita_config['postgres']['HOST'], + user=qiita_config['postgres']['ADMIN_USER'], + password=qiita_config['postgres']['ADMIN_PASSWORD'], + port=qiita_config['postgres']['PORT']) +cursor = conn.cursor() + +# update conda env for qiita private plugins +sql = "UPDATE qiita.software SET environment_script = 'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qiita' WHERE description = 'Internal Qiita jobs';" +cursor.execute(sql) +conn.commit() +if is_test: fps_plugin_configs = glob('/qiita_plugins/*.conf') print("Updating plugin credentials in dummy test DB with actual values from %i plugins." % len(fps_plugin_configs)) for i, fp_plugin_config in enumerate(fps_plugin_configs): From 47e932005843ee417fefe593039ec98f1833a207 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Mar 2025 10:03:15 +0100 Subject: [PATCH 077/287] ignore will shadow src in my IDE --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8d99ff1..897a633 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ environments/*.env logs/* .built_image_* Certificates/* -src/* From 6c3e316c7f52a37f241132565decce8d3d8b47a8 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Mar 2025 10:03:40 +0100 Subject: [PATCH 078/287] fix get_time issues when validating BIOM artifacts --- Images/qtp-biom/qtp-biom.dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 511692b..460b19e 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -14,6 +14,10 @@ RUN apt-get -y --fix-missing install \ gcc \ build-essential +# biom artifact validation throws an error since provenance tracking of Qiime2 cannot get proper time zone information, if not configured here +# https://stackoverflow.com/questions/21717411/timezone-information-missing-in-pytz +RUN dpkg-reconfigure -f noninteractive tzdata + # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ From cfd0646b50067909709722b2ae8e8aae1afe59e6 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Mar 2025 10:07:15 +0100 Subject: [PATCH 079/287] also mount qiita src to workers --- compose.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/compose.yaml b/compose.yaml index f0bf495..bf38a1f 100644 --- a/compose.yaml +++ b/compose.yaml @@ -85,6 +85,7 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - server-plugin-configs:/qiita_plugins - server-certificates:/qiita_certificates + - ./src/qiita:/qiita:U # - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh networks: - qiita-net From 316618080882547389f63892ed29df9c03205def Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 7 Mar 2025 17:34:29 +0100 Subject: [PATCH 080/287] hide workflows to NOT filter commands for artifact processing --- Images/qiita/qiita.dockerfile | 2 ++ Images/qiita/start_qiita-initDB.sh | 6 ++++++ Makefile | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index 22287a3..b185724 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -75,4 +75,6 @@ RUN rm -rf /qiita/qiita_core/support_files # hide default configurations from github sources RUN rm -f /qiita/qiita_pet/nginx_example.conf /qiita/qiita_pet/supervisor_example.conf /qiita/qiita_pet/support_files/config_portal.cfg +COPY drop_workflows.py /drop_workflows.py + # CMD ["conda", "run", "-n", "qiita"] diff --git a/Images/qiita/start_qiita-initDB.sh b/Images/qiita/start_qiita-initDB.sh index 62aeaf2..6c9f45b 100644 --- a/Images/qiita/start_qiita-initDB.sh +++ b/Images/qiita/start_qiita-initDB.sh @@ -8,3 +8,9 @@ ENV_NAME=qiita source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true # To avoid confusing the user, STDERR is written into a file and only reported if it does not contain the text that we expect to see if it just reports the existing DB grep 'already present on the system. You can drop it by running' .env-make.err > /dev/null || cat .env-make.err + + +# currently, commands with which you can process artifacts are limited to those that are present in available "recommended workflows". +# As they are not properly set up in the test database, we e.g. cannot run "deblur" on demux or trimmed existing artifacts (it's different in workflows in construction) +# As long as we don't have a nice mechanism to carry over recommended workflow, we better remove them altogether +source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; python /drop_workflows.py diff --git a/Makefile b/Makefile index d6b0bd5..2e73dc5 100644 --- a/Makefile +++ b/Makefile @@ -84,7 +84,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ chmod a+rw ./logs/nginx_access.log ./logs/nginx_error.log touch .built_image_nginx -.built_image_qiita: Images/qiita/qiita.dockerfile Images/qiita/config_qiita_oidc.cfg Images/qiita/start_qiita.sh Images/qiita/start_qiita-initDB.sh Images/qiita/supervisor_foreground.conf Images/qiita/start_plugin.py Images/qiita/config_portal.cfg +.built_image_qiita: Images/qiita/qiita.dockerfile Images/qiita/config_qiita_oidc.cfg Images/qiita/start_qiita.sh Images/qiita/start_qiita-initDB.sh Images/qiita/supervisor_foreground.conf Images/qiita/start_plugin.py Images/qiita/config_portal.cfg Images/qiita/drop_workflows.py test -d src/qiita || git clone -b auth_oidc https://github.com/jlab/qiita.git src/qiita # remove configuration and certificate files from upstream qiita repo rm -rf src/qiita/qiita_core/support_files From 8f612601e8354179aa44e241f9f6c4160c51f4f7 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 11 Mar 2025 12:05:52 +0100 Subject: [PATCH 081/287] refactor in a sense that docker prefix "qiita-container-anna-" must no longer given at too many positions --- Images/qiita/drop_workflows.py | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Images/qiita/drop_workflows.py diff --git a/Images/qiita/drop_workflows.py b/Images/qiita/drop_workflows.py new file mode 100644 index 0000000..aa45d90 --- /dev/null +++ b/Images/qiita/drop_workflows.py @@ -0,0 +1,67 @@ +import qiita_db as qdb +import sys + + +def remove(self): + # store for later, after table entry is dropped + workflow_name = self.name + + def _get_workflow_id(name): + with qdb.sql_connection.TRN: + sql = """SELECT default_workflow_id + FROM qiita.default_workflow + WHERE name = %s""" + qdb.sql_connection.TRN.add(sql, [name]) + return qdb.sql_connection.TRN.execute_fetchlast() + def _get_node_ids(workflow_id): + with qdb.sql_connection.TRN: + sql = """SELECT default_workflow_node_id + FROM qiita.default_workflow_node + WHERE default_workflow_id = %s""" + qdb.sql_connection.TRN.add(sql, [workflow_id]) + return qdb.sql_connection.TRN.execute_fetchflatten() + def _get_edge_ids(node_ids): + if len(node_ids) > 0: + with qdb.sql_connection.TRN: + sql = """SELECT default_workflow_edge_id + FROM qiita.default_workflow_edge + WHERE parent_id in %s OR child_id in %s""" + qdb.sql_connection.TRN.add(sql, [tuple(node_ids), tuple(node_ids)]) + return qdb.sql_connection.TRN.execute_fetchflatten() + else: + return [] + + workflow_id = _get_workflow_id(self.name) + node_ids = _get_node_ids(workflow_id) + edge_ids = _get_edge_ids(node_ids) + with qdb.sql_connection.TRN: + if len(edge_ids) > 0: + sql = """DELETE FROM qiita.default_workflow_edge_connections + WHERE default_workflow_edge_id in %s""" + qdb.sql_connection.TRN.add(sql, [tuple(edge_ids)]) + + sql = """DELETE FROM qiita.default_workflow_edge + WHERE default_workflow_edge_id in %s""" + qdb.sql_connection.TRN.add(sql, [tuple(edge_ids)]) + + if workflow_id is not None: + sql = """DELETE FROM qiita.default_workflow_node + WHERE default_workflow_id = %s""" + qdb.sql_connection.TRN.add(sql, [workflow_id]) + + sql = """DELETE FROM qiita.default_workflow_data_type + WHERE default_workflow_id = %s""" + qdb.sql_connection.TRN.add(sql, [workflow_id]) + + sql = """DELETE FROM qiita.default_workflow + WHERE default_workflow_id = %s""" + qdb.sql_connection.TRN.add(sql, [workflow_id]) + print("removed workflow '%s': ID=%i with %i nodes and %i edges" % (workflow_name, workflow_id, len(node_ids), len(edge_ids)), file=sys.stderr) + +def remove_workflows(): + for w in qdb.software.DefaultWorkflow.iter(): + w.remove = remove + w.remove(w) + + +remove_workflows() From 3f4318bdb7f331fa7c97592acea9c727a2345491 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 11 Mar 2025 15:44:23 +0100 Subject: [PATCH 082/287] make certificates in tmp dir + inject docker prefix --- Makefile | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 2e73dc5..adb8949 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ PODMAN_FLAGS = PODMAN_BIN = docker buildx CERTNAME=stefan OPENSSL=/bin/openssl +# docker compose prepends name of directory to containers +DOCKER_PREFIX=$(shell basename `pwd`)- TMPDIR := $(shell mktemp -d) ifeq ($(origin tmpdir), undefined) @@ -12,13 +14,14 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s # === create own certificates === mkdir -p Certificates/ # Generate a new root CA private key and certificate - cd $@/ && $(OPENSSL) req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=qiita-container-anna-qiita-1/C=DE/L=Giessen" -keyout $(CERTNAME)_rootca.key -out $(CERTNAME)_rootca.crt + cd $@/ && $(OPENSSL) req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=$(DOCKER_PREFIX)-1/C=DE/L=Giessen" -keyout $(CERTNAME)_rootca.key -out $(CERTNAME)_rootca.crt # Generate a new server private key cd $@/ && $(OPENSSL) genrsa -out $(CERTNAME)_server.key 2048 # Copy the following to a new file named csr.conf and modify to suit your needs # Copy the following to a new file named cert.conf and modify to suit your needs # Nils: alt_names is the important aspect. Make entries for all valid hostnames with which services shall be addressed - cp $^ $@/ + for f in `echo "$^"`; do cat $$f | sed "s/PREFIX/$(DOCKER_PREFIX)/g" > $@/`basename $$f`; done + #cp $^ $@/ # Generate a certificate signing request cd $@/ && $(OPENSSL) req -new -key $(CERTNAME)_server.key -out $(CERTNAME)_server.csr -config $(CERTNAME)_csr.conf # Generate a new signed server.crt to use with your server.key @@ -93,8 +96,9 @@ plugin: Images/qtp-biom/trigger.py Certificates/ .built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh tmpdir=$(TMPDIR) $(MAKE) plugin - cp -r Certificates/ Images/plugin_collector/ - cd Images/plugin_collector && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-plugin_collector + cp $^ $(TMPDIR) + cp -r Certificates/ $(tmpdir)/ + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur .built_image_qp-qiime2 .built_image_qp-qiime2 .built_image_qtp-job-output-folder @@ -108,4 +112,8 @@ environments/qiita.env: environments/qiita.env.example config: environments/qiita_db.env environments/qiita.env +make clean: + rm .built_image_* + rm -rf Certificates + all: config images From eb71b4b048448dd63a44efa4982e5c3fa23611ca Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 11 Mar 2025 15:45:04 +0100 Subject: [PATCH 083/287] remove unneccessary lines from startup scripts --- Images/qp-deblur/start_qp-deblur.sh | 12 ------------ Images/qp-qiime2/start_qp-qiime2.sh | 12 ------------ Images/qp-target-gene/start_qp-target-gene.sh | 12 ------------ Images/qtp-biom/start_qtp-biom.sh | 12 ------------ Images/qtp-diversity/start_qtp-diversity.sh | 12 ------------ .../start_qtp-job-output-folder.sh | 12 ------------ Images/qtp-sequencing/start_qtp-sequencing.sh | 12 ------------ Images/qtp-visualization/start_qtp-visualization.sh | 12 ------------ 8 files changed, 96 deletions(-) diff --git a/Images/qp-deblur/start_qp-deblur.sh b/Images/qp-deblur/start_qp-deblur.sh index c1639e8..a8b9bac 100644 --- a/Images/qp-deblur/start_qp-deblur.sh +++ b/Images/qp-deblur/start_qp-deblur.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qp-deblur - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py deblur start_deblur /qp-deblur tail -f /dev/null diff --git a/Images/qp-qiime2/start_qp-qiime2.sh b/Images/qp-qiime2/start_qp-qiime2.sh index 72337ab..50069a0 100644 --- a/Images/qp-qiime2/start_qp-qiime2.sh +++ b/Images/qp-qiime2/start_qp-qiime2.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qp-qiime2 - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py qiime2 start_qiime2 /qp-qiime2 tail -f /dev/null diff --git a/Images/qp-target-gene/start_qp-target-gene.sh b/Images/qp-target-gene/start_qp-target-gene.sh index 5fdfed7..9749354 100644 --- a/Images/qp-target-gene/start_qp-target-gene.sh +++ b/Images/qp-target-gene/start_qp-target-gene.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qp-target-gene - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py qp-target-gene start_target_gene /qp-target-gene tail -f /dev/null diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index 1e2d9ba..3ab12c4 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qtp-biom - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py qtp-biom start_biom /qtp-biom tail -f /dev/null diff --git a/Images/qtp-diversity/start_qtp-diversity.sh b/Images/qtp-diversity/start_qtp-diversity.sh index ba217c8..889173f 100644 --- a/Images/qtp-diversity/start_qtp-diversity.sh +++ b/Images/qtp-diversity/start_qtp-diversity.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qtp-sequencing - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py qiime2 start_diversity_types /qtp-diversity tail -f /dev/null diff --git a/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh b/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh index 8863b74..cdc5f27 100644 --- a/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh +++ b/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qtp-sequencing - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py qtp-job-output-folder start_qtp_job_output_folder /qtp-job-output-folder tail -f /dev/null diff --git a/Images/qtp-sequencing/start_qtp-sequencing.sh b/Images/qtp-sequencing/start_qtp-sequencing.sh index d4d0494..a740816 100644 --- a/Images/qtp-sequencing/start_qtp-sequencing.sh +++ b/Images/qtp-sequencing/start_qtp-sequencing.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qtp-sequencing - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py qtp-sequencing start_qtp_sequencing /qtp-sequencing tail -f /dev/null diff --git a/Images/qtp-visualization/start_qtp-visualization.sh b/Images/qtp-visualization/start_qtp-visualization.sh index ec5e941..f3aeebe 100644 --- a/Images/qtp-visualization/start_qtp-visualization.sh +++ b/Images/qtp-visualization/start_qtp-visualization.sh @@ -1,17 +1,5 @@ #!/bin/bash -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qtp-sequencing - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py cd / && python trigger.py qtp-visualization start_visualization_types /qtp-visualization tail -f /dev/null From 1047bcbb26e6c7bc86ba05f250220c14e7843fdb Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 11 Mar 2025 15:45:45 +0100 Subject: [PATCH 084/287] make certificate creation more flexible with regards to docker prefix --- Images/plugin_collector/stefan_cert.conf | 10 +++++----- Images/plugin_collector/stefan_csr.conf | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Images/plugin_collector/stefan_cert.conf b/Images/plugin_collector/stefan_cert.conf index 9479793..cb9531d 100644 --- a/Images/plugin_collector/stefan_cert.conf +++ b/Images/plugin_collector/stefan_cert.conf @@ -5,8 +5,8 @@ subjectAltName = @alt_names [alt_names] DNS.1 = localhost -DNS.2 = qiita-container-anna-qiita-1 -DNS.3 = qiita-container-anna-qiita-worker-1 -DNS.4 = qiita-container-anna-qiita-worker-2 -DNS.5 = qiita-container-anna-qiita-worker-3 -DNS.6 = qiita-container-anna-nginx-1 \ No newline at end of file +DNS.2 = PREFIXqiita-1 +DNS.3 = PREFIXqiita-worker-1 +DNS.4 = PREFIXqiita-worker-2 +DNS.5 = PREFIXqiita-worker-3 +DNS.6 = PREFIXnginx-1 diff --git a/Images/plugin_collector/stefan_csr.conf b/Images/plugin_collector/stefan_csr.conf index 2f42bb4..ca7ed1c 100644 --- a/Images/plugin_collector/stefan_csr.conf +++ b/Images/plugin_collector/stefan_csr.conf @@ -19,8 +19,8 @@ subjectAltName = @alt_names [ alt_names ] DNS.1 = localhost IP.1 = 127.0.0.1 -DNS.2 = qiita-container-anna-qiita-1 -DNS.3 = qiita-container-anna-qiita-worker-1 -DNS.4 = qiita-container-anna-qiita-worker-2 -DNS.5 = qiita-container-anna-qiita-worker-3 -DNS.6 = qiita-container-anna-nginx-1 \ No newline at end of file +DNS.2 = PREFIXqiita-1 +DNS.3 = PREFIXqiita-worker-1 +DNS.4 = PREFIXqiita-worker-2 +DNS.5 = PREFIXqiita-worker-3 +DNS.6 = PREFIXnginx-1 From 78b16e3c94ea76223f79351f381ed1b9720bb65c Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 11 Mar 2025 15:46:32 +0100 Subject: [PATCH 085/287] avoid hard coding of docker prefix --- Images/plugin_collector/collect_configs.py | 3 ++- Images/qiita/start_plugin.py | 3 ++- compose.yaml | 15 +++++++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Images/plugin_collector/collect_configs.py b/Images/plugin_collector/collect_configs.py index 24c745b..5dfb7a8 100644 --- a/Images/plugin_collector/collect_configs.py +++ b/Images/plugin_collector/collect_configs.py @@ -10,6 +10,7 @@ raise ValueError("No qiita plugins given for which configuration files should be retrieved! Environment variable '%s' not set!" % ENV_PLUGINS) var_plugins = os.environ['QIITA_PLUGINS'] +docker_prefix = os.environ['DOCKER_PREFIX'] # strip potential quotes if var_plugins.startswith('"') or var_plugins.startswith("'"): var_plugins = var_plugins[1:] @@ -23,7 +24,7 @@ if container == "": continue print(' (%i/%i) %s' % (i+1, len(containers), container), end="", file=sys.stderr) - url = 'http://qiita-container-anna-%s-1:%s/%s' % (container, PORT, API_ENDPOINT) + url = 'http://%s%s-1:%s/%s' % (docker_prefix, container, PORT, API_ENDPOINT) print(" '%s'" % url, end="", file=sys.stderr) req = requests.get(url) diff --git a/Images/qiita/start_plugin.py b/Images/qiita/start_plugin.py index d1df576..c5cc114 100644 --- a/Images/qiita/start_plugin.py +++ b/Images/qiita/start_plugin.py @@ -8,7 +8,8 @@ pluginname, qiita_server_url, job_id, output_dir = sys.argv[1:] -req = requests.post('http://qiita-container-anna-%s-1:%s/run' % (pluginname, PORT), +docker_prefix = os.environ['DOCKER_PREFIX'] +req = requests.post('http://%s%s-1:%s/run' % (docker_prefix, pluginname, PORT), json={'url': qiita_server_url, 'job_id': job_id, 'output_dir': output_dir}) diff --git a/compose.yaml b/compose.yaml index 544db6c..6704f82 100644 --- a/compose.yaml +++ b/compose.yaml @@ -61,6 +61,7 @@ services: - PORT=21174 - MASTER=--master - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - DOCKER_PREFIX=qiita-container-anna- volumes: - qiita-data:/qiita_data - ./src/qiita:/qiita:U @@ -102,6 +103,7 @@ services: - PORT=21175 - MASTER= - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - DOCKER_PREFIX=qiita-container-anna- volumes: - qiita-data:/qiita_data - ./logs:/logs @@ -197,11 +199,13 @@ services: volumes: - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./src/qtp-biom:/qtp-biom:U environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -220,6 +224,7 @@ services: - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -238,6 +243,7 @@ services: - REQUESTS_CA_BUNDLE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -256,6 +262,7 @@ services: - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -274,6 +281,7 @@ services: - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -287,11 +295,13 @@ services: volumes: - qiita-data:/qiita_data - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./src/qtp-biom:/qtp-biom:U environment: # TODO: is there a more elegant way to obtain this path? - REQUESTS_CA_BUNDLE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -310,6 +320,7 @@ services: - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -328,6 +339,7 @@ services: - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem - SSL_CERT_FILE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -343,8 +355,6 @@ services: - server-plugin-configs:/qiita_plugins - qiita-data:/qiita_data - server-certificates:/qiita_certificates - #- /Daten/Git/jlab/qiita-container-anna/Images/plugin_collector/collect_configs.py:/collect.py - #- /Daten/Git/jlab/qiita-container-anna/Images/plugin_collector/fix_test_db.py:/fix_test_db.py depends_on: qiita-initialize-db: condition: service_completed_successfully @@ -365,6 +375,7 @@ services: qtp-job-output-folder: condition: service_started environment: + - DOCKER_PREFIX=qiita-container-anna- - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" command: ['/startup_plugin_collector.sh'] From 363a70ed1971029e7d36b0386f14f8503c7194f9 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 11 Mar 2025 16:18:56 +0100 Subject: [PATCH 086/287] found an even better way to avoid basename project names: field "name" as top level in compose file --- Images/nginx/nginx_qiita.conf | 6 +++--- Images/plugin_collector/collect_configs.py | 3 +-- Images/plugin_collector/stefan_cert.conf | 10 +++++----- Images/plugin_collector/stefan_csr.conf | 10 +++++----- Images/qiita/start_plugin.py | 3 +-- Makefile | 9 +++++---- compose.yaml | 5 ++--- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Images/nginx/nginx_qiita.conf b/Images/nginx/nginx_qiita.conf index ae2f2e0..8e0772e 100644 --- a/Images/nginx/nginx_qiita.conf +++ b/Images/nginx/nginx_qiita.conf @@ -13,9 +13,9 @@ http { # ports to redirect for mainqiita upstream mainqiita { server qiita:21174; - server qiita-container-anna-qiita-worker-1:21175; - server qiita-container-anna-qiita-worker-2:21175; - server qiita-container-anna-qiita-worker-3:21175; + server tinqiita-qiita-worker-1:21175; + server tinqiita-qiita-worker-2:21175; + server tinqiita-qiita-worker-3:21175; } # define variables for the actions that shall be taken for websocket handshake diff --git a/Images/plugin_collector/collect_configs.py b/Images/plugin_collector/collect_configs.py index 5dfb7a8..0637bf8 100644 --- a/Images/plugin_collector/collect_configs.py +++ b/Images/plugin_collector/collect_configs.py @@ -10,7 +10,6 @@ raise ValueError("No qiita plugins given for which configuration files should be retrieved! Environment variable '%s' not set!" % ENV_PLUGINS) var_plugins = os.environ['QIITA_PLUGINS'] -docker_prefix = os.environ['DOCKER_PREFIX'] # strip potential quotes if var_plugins.startswith('"') or var_plugins.startswith("'"): var_plugins = var_plugins[1:] @@ -24,7 +23,7 @@ if container == "": continue print(' (%i/%i) %s' % (i+1, len(containers), container), end="", file=sys.stderr) - url = 'http://%s%s-1:%s/%s' % (docker_prefix, container, PORT, API_ENDPOINT) + url = 'http://%s%s-1:%s/%s' % ('tinqiita-', container, PORT, API_ENDPOINT) print(" '%s'" % url, end="", file=sys.stderr) req = requests.get(url) diff --git a/Images/plugin_collector/stefan_cert.conf b/Images/plugin_collector/stefan_cert.conf index cb9531d..2eb1ee9 100644 --- a/Images/plugin_collector/stefan_cert.conf +++ b/Images/plugin_collector/stefan_cert.conf @@ -5,8 +5,8 @@ subjectAltName = @alt_names [alt_names] DNS.1 = localhost -DNS.2 = PREFIXqiita-1 -DNS.3 = PREFIXqiita-worker-1 -DNS.4 = PREFIXqiita-worker-2 -DNS.5 = PREFIXqiita-worker-3 -DNS.6 = PREFIXnginx-1 +DNS.2 = tinqiita-qiita-1 +DNS.3 = tinqiita-qiita-worker-1 +DNS.4 = tinqiita-qiita-worker-2 +DNS.5 = tinqiita-qiita-worker-3 +DNS.6 = tinqiita-nginx-1 diff --git a/Images/plugin_collector/stefan_csr.conf b/Images/plugin_collector/stefan_csr.conf index ca7ed1c..011124a 100644 --- a/Images/plugin_collector/stefan_csr.conf +++ b/Images/plugin_collector/stefan_csr.conf @@ -19,8 +19,8 @@ subjectAltName = @alt_names [ alt_names ] DNS.1 = localhost IP.1 = 127.0.0.1 -DNS.2 = PREFIXqiita-1 -DNS.3 = PREFIXqiita-worker-1 -DNS.4 = PREFIXqiita-worker-2 -DNS.5 = PREFIXqiita-worker-3 -DNS.6 = PREFIXnginx-1 +DNS.2 = tinqiita-qiita-1 +DNS.3 = tinqiita-qiita-worker-1 +DNS.4 = tinqiita-qiita-worker-2 +DNS.5 = tinqiita-qiita-worker-3 +DNS.6 = tinqiita-nginx-1 diff --git a/Images/qiita/start_plugin.py b/Images/qiita/start_plugin.py index c5cc114..5709f63 100644 --- a/Images/qiita/start_plugin.py +++ b/Images/qiita/start_plugin.py @@ -8,8 +8,7 @@ pluginname, qiita_server_url, job_id, output_dir = sys.argv[1:] -docker_prefix = os.environ['DOCKER_PREFIX'] -req = requests.post('http://%s%s-1:%s/run' % (docker_prefix, pluginname, PORT), +req = requests.post('http://%s%s-1:%s/run' % ('tinqiita-', pluginname, PORT), json={'url': qiita_server_url, 'job_id': job_id, 'output_dir': output_dir}) diff --git a/Makefile b/Makefile index adb8949..82cb5b1 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,6 @@ PODMAN_BIN = docker buildx CERTNAME=stefan OPENSSL=/bin/openssl # docker compose prepends name of directory to containers -DOCKER_PREFIX=$(shell basename `pwd`)- TMPDIR := $(shell mktemp -d) ifeq ($(origin tmpdir), undefined) @@ -14,13 +13,13 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s # === create own certificates === mkdir -p Certificates/ # Generate a new root CA private key and certificate - cd $@/ && $(OPENSSL) req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=$(DOCKER_PREFIX)-1/C=DE/L=Giessen" -keyout $(CERTNAME)_rootca.key -out $(CERTNAME)_rootca.crt + cd $@/ && $(OPENSSL) req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=tinqiita-nginx-1/C=DE/L=Giessen" -keyout $(CERTNAME)_rootca.key -out $(CERTNAME)_rootca.crt # Generate a new server private key cd $@/ && $(OPENSSL) genrsa -out $(CERTNAME)_server.key 2048 # Copy the following to a new file named csr.conf and modify to suit your needs # Copy the following to a new file named cert.conf and modify to suit your needs # Nils: alt_names is the important aspect. Make entries for all valid hostnames with which services shall be addressed - for f in `echo "$^"`; do cat $$f | sed "s/PREFIX/$(DOCKER_PREFIX)/g" > $@/`basename $$f`; done + for f in `echo "$^"`; do cat $$f > $@/`basename $$f`; done #cp $^ $@/ # Generate a certificate signing request cd $@/ && $(OPENSSL) req -new -key $(CERTNAME)_server.key -out $(CERTNAME)_server.csr -config $(CERTNAME)_csr.conf @@ -91,7 +90,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ test -d src/qiita || git clone -b auth_oidc https://github.com/jlab/qiita.git src/qiita # remove configuration and certificate files from upstream qiita repo rm -rf src/qiita/qiita_core/support_files - cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita + cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita --no-cache touch .built_image_qiita .built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh @@ -115,5 +114,7 @@ config: environments/qiita_db.env environments/qiita.env make clean: rm .built_image_* rm -rf Certificates + rm -rf /var/lib/docker/volumes/tinqiita_server-certificates/_data/* + rm -rf /var/lib/docker/volumes/tinqiita_server-plugin-configs/_data/* all: config images diff --git a/compose.yaml b/compose.yaml index 6704f82..cfff263 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,3 +1,5 @@ +name: tinqiita + services: qiita-db: image: postgres:15 @@ -61,7 +63,6 @@ services: - PORT=21174 - MASTER=--master - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - DOCKER_PREFIX=qiita-container-anna- volumes: - qiita-data:/qiita_data - ./src/qiita:/qiita:U @@ -103,7 +104,6 @@ services: - PORT=21175 - MASTER= - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - DOCKER_PREFIX=qiita-container-anna- volumes: - qiita-data:/qiita_data - ./logs:/logs @@ -375,7 +375,6 @@ services: qtp-job-output-folder: condition: service_started environment: - - DOCKER_PREFIX=qiita-container-anna- - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" command: ['/startup_plugin_collector.sh'] From c25c8db51c12df792e51fbcbb55ddfb6e0bd2fbf Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 11 Mar 2025 16:34:44 +0100 Subject: [PATCH 087/287] update base url --- Images/qiita/config_qiita_oidc.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qiita/config_qiita_oidc.cfg b/Images/qiita/config_qiita_oidc.cfg index bc1511e..273e03d 100644 --- a/Images/qiita/config_qiita_oidc.cfg +++ b/Images/qiita/config_qiita_oidc.cfg @@ -23,7 +23,7 @@ LOG_DIR = /logs/ REQUIRE_APPROVAL = True # Base URL: DO NOT ADD TRAILING SLASH -BASE_URL = https://qiita-container-anna-nginx-1:8383 +BASE_URL = https://tinqiita-nginx-1:8383 # Download path files UPLOAD_DATA_DIR = /qiita_data/uploads/ From 2f5354d9eeb28f29dd9fbcc815229e517eb9db79 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 14 Mar 2025 12:10:47 +0100 Subject: [PATCH 088/287] add aspera for ENA submission --- Images/qiita/qiita.dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index b185724..2a69b06 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -77,4 +77,7 @@ RUN rm -f /qiita/qiita_pet/nginx_example.conf /qiita/qiita_pet/supervisor_exampl COPY drop_workflows.py /drop_workflows.py +# install aspera client for ENA submission +RUN conda install hcc::aspera-cli + # CMD ["conda", "run", "-n", "qiita"] From c40668ee1cb7fdce09da2a24a4e69782c220cac7 Mon Sep 17 00:00:00 2001 From: svdlh Date: Tue, 22 Apr 2025 11:15:54 +0200 Subject: [PATCH 089/287] fixed parameter --server-cert to --ca-cert --- Images/qtp-diversity/qtp-diversity.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-diversity/qtp-diversity.dockerfile b/Images/qtp-diversity/qtp-diversity.dockerfile index e2ba8b8..098a481 100644 --- a/Images/qtp-diversity/qtp-diversity.dockerfile +++ b/Images/qtp-diversity/qtp-diversity.dockerfile @@ -66,7 +66,7 @@ RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN chmod u+x /qtp-diversity/scripts/configure_diversity_types /qtp-diversity/scripts/start_diversity_types -RUN /qtp-diversity/scripts/configure_diversity_types --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN /qtp-diversity/scripts/configure_diversity_types --env-script "true" --ca-cert /unshared_certificates/stefan_server.crt RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-diversity/" /unshared_plugins/*.conf CMD ["./start_qtp-diversity.sh"] From f1cece033a64d91bf5ced18b1cbac2e1cc84f97e Mon Sep 17 00:00:00 2001 From: svdlh Date: Tue, 22 Apr 2025 11:44:09 +0200 Subject: [PATCH 090/287] switched --server-cert to --ca-cert --- Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile index ab32e36..eccff6e 100644 --- a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile +++ b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile @@ -60,7 +60,7 @@ RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN chmod u+x /qtp-job-output-folder/scripts/configure_qtp_job_output_folder /qtp-job-output-folder/scripts/start_qtp_job_output_folder -RUN /qtp-job-output-folder/scripts/configure_qtp_job_output_folder --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN /qtp-job-output-folder/scripts/configure_qtp_job_output_folder --env-script "true" --ca-cert /unshared_certificates/stefan_server.crt RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-job-output-folder/" /unshared_plugins/*.conf CMD ["./start_qtp-job-output-folder.sh"] From 824bbb317f5d0f869f413ca964dbc5a389f7fd83 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 8 May 2025 13:06:14 +0200 Subject: [PATCH 091/287] intermediate state of rewrite --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index c828284..4b23b2c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,32 @@ +## Howto start-up qiita through docker compose +Note: this does currently **not** work with podman :-( So strictly stick to docker here. + +1. We assume you operate on your local computer, i.e. not within the BCF cluster as you won't have docker, on a Ubuntu/Mint like OS. +2. Install necessary software (git, docker.io): `sudo apt-get install git docker.io` +3. Install docker-compose: + - You need to register their apt repository first: see https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository for details). In short: copy & paste the following command and execute in terminal: + ``` + # Add Docker's official GPG key: + sudo apt-get update + sudo apt-get install ca-certificates curl + sudo install -m 0755 -d /etc/apt/keyrings + sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + sudo chmod a+r /etc/apt/keyrings/docker.asc + + # Add the repository to Apt sources: + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + sudo apt-get update + ``` + - Install docker-compose through apt: `sudo apt-get update && sudo apt-get install docker-compose-plugin` +4. clone a local copy of this repository, branch "tinqiita": `git clone -b tinqiita https://github.com/jlab/qiita-keycloak.git tinqiita` +5. change into this new directory: `cd tinqiita` +6. create necessary images and other files (as this will create multiple docker images, it can take quite some time, approx. 30min?!): `sudo make all` + + + **IMPORTANT: Have docker installed!** **THIS VERSION CURRENTLY ONLY WORKS WITH DOCKER, NOT WITH PODMAN** **FOR TESTING ON LOCAL MACHINES** From 342a87ea4ee15cfb4f212155b81248e61bbef5b5 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 8 May 2025 14:33:06 +0200 Subject: [PATCH 092/287] use cache for docker image creation for qiita + clone qtp-biom first --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 82cb5b1..90927b7 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ cp -r $^ $(tmpdir)/ .built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh + test -d src/qtp-biom || git clone https://github.com/qiita-spots/qtp-biom.git src/qtp-biom tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` @@ -90,7 +91,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ test -d src/qiita || git clone -b auth_oidc https://github.com/jlab/qiita.git src/qiita # remove configuration and certificate files from upstream qiita repo rm -rf src/qiita/qiita_core/support_files - cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita --no-cache + cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita touch .built_image_qiita .built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh From c94955dc0909e5ad866d046e5eafc6459bc8efc1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 8 May 2025 14:50:34 +0200 Subject: [PATCH 093/287] Update README.md --- README.md | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 4b23b2c..590ff1d 100644 --- a/README.md +++ b/README.md @@ -24,27 +24,20 @@ Note: this does currently **not** work with podman :-( So strictly stick to dock 4. clone a local copy of this repository, branch "tinqiita": `git clone -b tinqiita https://github.com/jlab/qiita-keycloak.git tinqiita` 5. change into this new directory: `cd tinqiita` 6. create necessary images and other files (as this will create multiple docker images, it can take quite some time, approx. 30min?!): `sudo make all` +7. start the docker ensemble: `sudo docker compose up` +8. take your favorite browser and surf to `https://localhost:8383`. You probably get a warning due to incorrect SSL certificates like: + ![image](https://github.com/user-attachments/assets/58e978ab-c633-4197-b6f9-b0a62b8b671c) for Firefox. Press "Advanced..." and then "Accept the Risk and Continue" +9. You should now be able to see your living qiita. Log in as user `admin@foo.bar` (or `test@foo.bar`) and password `password`. +That's it. Enjoy! +### pro infos +- log files will be written to `tinqiita/logs` +- You can access the relevant containers by checking for their names with `sudo docker container ls` and then running `sudo docker exec -it bash` +- keycloak service is **not** activated at the moment of writing, but should you want to work on that: + 1. Run `sudo docker compose up keycloak keycloakdb` + 2. Open `http://localhost:8080`, login admin pw admin + 3. Configure Qiita as a service, create a user. + 4. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, remove # from necessary oidc block, change SUPERSECRETSTRING. -**IMPORTANT: Have docker installed!** -**THIS VERSION CURRENTLY ONLY WORKS WITH DOCKER, NOT WITH PODMAN** -**FOR TESTING ON LOCAL MACHINES** -### Hopefully "foolproof" instructions: -0. Log files will be mounted at qiita_logs on your local machine in this repo directory. Otherwise, change the file path to your desired path in the compose file as well as in the qiita, nginx and supervisord conf. -1. Clone repository -2. Move into Image Folder `cd Images/qiita` -3. Build docker image `sudo docker build . -f qiita/Dockerfile -t local-qiita` -4. Build the nginx Image the same way as the qiita image, only in the nginx folder, using the image tag `local-nginx_qiita`. -5. Repeat with qtp-biom Image as `local-qtp-biom`. -6. Move to folder containing compose file `cd ../..` -7. Copy the `qiita_db.env.example` and the `qiita.env.example` files, configure them to your needs, and delete the `.example` from the file names. -8. Run `sudo docker compose up keycloak keycloakdb` -9. Open `http://localhost:8080`, login admin pw admin -10. Configure Qiita as a service, create a user. -11. Edit `config_qiita_oidc.cfg` to fit your local Keycloak configuration, remove # from necessary oidc block, change SUPERSECRETSTRING. -12. Run docker compose `sudo docker compose up qiita qiita-db redis qiita_worker nginx` -- Due to some unforseen problem I did not want to deal with, yet, the original "database existence" check does not work anymore. You might have to adjust the command in start_qiita.sh the first time you run it to create your database :/ -13. You can access the relevant containers by checking for their names with `sudo docker container ls` and then running `sudo docker exec -it bash` -14. Open `http://localhost:8383` From 8bab5d955ca0c43136ed71fb7ae901fe2ac9e2e6 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 8 May 2025 15:32:41 +0200 Subject: [PATCH 094/287] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 590ff1d..1203502 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,12 @@ Note: this does currently **not** work with podman :-( So strictly stick to dock That's it. Enjoy! +## For plugin developers +To integrate your shiny new plugin into this docker compose version of Qiita, I suggest you use one of the existing plugins as template, e.g. "qp-deblur". +Remember to: + 1. **makefile**: create a make target for the docker image of your plugin, like https://github.com/jlab/qiita-keycloak/blob/c94955dc0909e5ad866d046e5eafc6459bc8efc1/Makefile#L65-L69 and add the target name to line https://github.com/jlab/qiita-keycloak/blob/c94955dc0909e5ad866d046e5eafc6459bc8efc1/Makefile#L104 + 2. **compose file**: copy and paste a "service" like here https://github.com/jlab/qiita-keycloak/blob/c94955dc0909e5ad866d046e5eafc6459bc8efc1/compose.yaml#L288-L306 and make your new "service" a dependency of the "plugin-collector" service here: https://github.com/jlab/qiita-keycloak/blob/c94955dc0909e5ad866d046e5eafc6459bc8efc1/compose.yaml#L371-L372 to also start-up this container with all others + let the plugin collector python script know about the existance of the new plugin by appending it's name to the string here: https://github.com/jlab/qiita-keycloak/blob/c94955dc0909e5ad866d046e5eafc6459bc8efc1/compose.yaml#L378 + ### pro infos - log files will be written to `tinqiita/logs` - You can access the relevant containers by checking for their names with `sudo docker container ls` and then running `sudo docker exec -it bash` From 36f3e7818ca5fd8dbc126237d10067b8871835a7 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 8 May 2025 15:33:08 +0200 Subject: [PATCH 095/287] ensure workdir for qiita exists --- Images/qiita/start_qiita-initDB.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Images/qiita/start_qiita-initDB.sh b/Images/qiita/start_qiita-initDB.sh index 6c9f45b..1fe3ffe 100644 --- a/Images/qiita/start_qiita-initDB.sh +++ b/Images/qiita/start_qiita-initDB.sh @@ -4,6 +4,9 @@ CONDA_DIR=/opt/conda ENV_NAME=qiita #PORT=21174 +# create (empty) workding directory as given in Qiita configuration +mkdir -p `grep ^WORKING_DIR $QIITA_CONFIG_FP | cut -d "=" -f 2` + # We execute qiita-env make every time. We expect that it will fail always but the very first time, as the qiita DB should exist from then on source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true # To avoid confusing the user, STDERR is written into a file and only reported if it does not contain the text that we expect to see if it just reports the existing DB From b4949db4c09e4f3a03471c6c335fa4b006c20ae1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 8 May 2025 15:35:51 +0200 Subject: [PATCH 096/287] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1203502..096dcd2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Howto start-up qiita through docker compose -Note: this does currently **not** work with podman :-( So strictly stick to docker here. +Note: this does currently **not** work with podman :-( So strictly stick to docker here. -1. We assume you operate on your local computer, i.e. not within the BCF cluster as you won't have docker, on a Ubuntu/Mint like OS. +1. We assume you operate on your local computer, i.e. not within the BCF cluster as you won't have docker, on a Ubuntu/Mint like OS. You will need approx. 55 GB free disk space. 2. Install necessary software (git, docker.io): `sudo apt-get install git docker.io` 3. Install docker-compose: - You need to register their apt repository first: see https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository for details). In short: copy & paste the following command and execute in terminal: From fd2e9e34c62a8c2dd5d9bb9ab8c0df6002900e30 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 9 May 2025 11:58:36 +0200 Subject: [PATCH 097/287] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 096dcd2..20d52f1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Note: this does currently **not** work with podman :-( So strictly stick to docker here. 1. We assume you operate on your local computer, i.e. not within the BCF cluster as you won't have docker, on a Ubuntu/Mint like OS. You will need approx. 55 GB free disk space. -2. Install necessary software (git, docker.io): `sudo apt-get install git docker.io` +2. Install necessary software (git, docker.io, postgresql-client-common): `sudo apt-get install git docker.io postgresql-client-common` 3. Install docker-compose: - You need to register their apt repository first: see https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository for details). In short: copy & paste the following command and execute in terminal: ``` From f3eea1fb097e34d31186e928d00c00fdbe6f2724 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 9 May 2025 14:27:03 +0200 Subject: [PATCH 098/287] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20d52f1..ec93ee9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Note: this does currently **not** work with podman :-( So strictly stick to docker here. 1. We assume you operate on your local computer, i.e. not within the BCF cluster as you won't have docker, on a Ubuntu/Mint like OS. You will need approx. 55 GB free disk space. -2. Install necessary software (git, docker.io, postgresql-client-common): `sudo apt-get install git docker.io postgresql-client-common` +2. Install necessary software (git, docker.io, postgresql-client): `sudo apt-get install git docker.io postgresql-client` 3. Install docker-compose: - You need to register their apt repository first: see https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository for details). In short: copy & paste the following command and execute in terminal: ``` From 817284e3e651b709a92efc8171bc5991e530bd5e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 9 May 2025 15:56:05 +0200 Subject: [PATCH 099/287] no extra volume names needed --- compose.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/compose.yaml b/compose.yaml index cfff263..dd53596 100644 --- a/compose.yaml +++ b/compose.yaml @@ -386,10 +386,8 @@ networks: volumes: postgres-data: - name: qiita-postgres-data #~ keycloak-postgres-data: #~ name: keycloak-postgres-data qiita-data: - name: qiita-data server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files server-certificates: # server one copy of qiita server (master and workers) certificate files. If not in volume, "plugin_collector" should copy them there From b6382f7a95c6e54d32fc47cb40fd97a8f7a6299e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 9 May 2025 15:56:20 +0200 Subject: [PATCH 100/287] give postgres some time to initialize before speaking against the DB --- Images/qiita/start_qiita-initDB.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Images/qiita/start_qiita-initDB.sh b/Images/qiita/start_qiita-initDB.sh index 1fe3ffe..86d9db0 100644 --- a/Images/qiita/start_qiita-initDB.sh +++ b/Images/qiita/start_qiita-initDB.sh @@ -7,6 +7,8 @@ ENV_NAME=qiita # create (empty) workding directory as given in Qiita configuration mkdir -p `grep ^WORKING_DIR $QIITA_CONFIG_FP | cut -d "=" -f 2` +sleep 5 # wait for postgress to boot up + # We execute qiita-env make every time. We expect that it will fail always but the very first time, as the qiita DB should exist from then on source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd /qiita; qiita-env make --no-load-ontologies 2> .env-make.err || true # To avoid confusing the user, STDERR is written into a file and only reported if it does not contain the text that we expect to see if it just reports the existing DB From f107037e2d33845da338a95046de206855847899 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 9 May 2025 15:56:51 +0200 Subject: [PATCH 101/287] always overwrite configuration collection with files found in plugins to keep oauth client_id and secret in sync --- Images/plugin_collector/collect_configs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Images/plugin_collector/collect_configs.py b/Images/plugin_collector/collect_configs.py index 0637bf8..39aa384 100644 --- a/Images/plugin_collector/collect_configs.py +++ b/Images/plugin_collector/collect_configs.py @@ -32,8 +32,8 @@ else: fp_config = '/qiita_plugins/%s.conf' % container if os.path.exists(fp_config): - print(" already present.", file=sys.stderr) - else: + print(" already present. Will overwrite", file=sys.stderr) # currently, we always want to overwrite configuration to match oauth token + if True: with open(fp_config, 'w') as f: f.write(req.content.decode('utf-8')) print(" ok.", file=sys.stderr) From 4bff551772f83f4a4a2433f4ea7c86be1eca4118 Mon Sep 17 00:00:00 2001 From: Tobias-Gr Date: Tue, 27 May 2025 16:10:40 +0200 Subject: [PATCH 102/287] added qp-multiqc dependencys (Makefile, compose.yaml, Images/qp-multiqc) --- .gitignore | 1 + Images/plugin_collector/fix_test_db.py | 3 + Images/qp-multiqc/qp-multiqc.dockerfile | 74 +++++++++++++++++++++++++ Images/qp-multiqc/start_qp-multiqc.sh | 19 +++++++ Makefile | 16 +++++- compose.yaml | 22 +++++++- 6 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 Images/qp-multiqc/qp-multiqc.dockerfile create mode 100644 Images/qp-multiqc/start_qp-multiqc.sh diff --git a/.gitignore b/.gitignore index 897a633..63dd0ee 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ environments/*.env logs/* .built_image_* Certificates/* +src/ diff --git a/Images/plugin_collector/fix_test_db.py b/Images/plugin_collector/fix_test_db.py index 7865708..bf1e383 100644 --- a/Images/plugin_collector/fix_test_db.py +++ b/Images/plugin_collector/fix_test_db.py @@ -33,6 +33,9 @@ SQL_get_softwareID_clientID = "SELECT software.software_id, oauth_software.client_id FROM qiita.software JOIN qiita.oauth_software ON qiita.software.software_id=qiita.oauth_software.software_id WHERE name='%s' AND version='%s';" % ( config['main']['name'], config['main']['version'] ) + + print(f" Plugin-Konfig: name='{config['main']['name']}', version='{config['main']['version']}'") + cursor.execute(SQL_get_softwareID_clientID) sql_result = cursor.fetchone() if sql_result is None: diff --git a/Images/qp-multiqc/qp-multiqc.dockerfile b/Images/qp-multiqc/qp-multiqc.dockerfile new file mode 100644 index 0000000..d75fdfc --- /dev/null +++ b/Images/qp-multiqc/qp-multiqc.dockerfile @@ -0,0 +1,74 @@ +# base image: ubuntu:24.04 +FROM ubuntu:24.04 + +ARG MINIFORGE_VERSION=24.1.2-0 + +# set environments +ENV CONDA_DIR=/opt/conda +ENV PATH=${CONDA_DIR}/bin:${PATH} + +# install system dependencies +RUN apt-get -y update +RUN apt-get -y --fix-missing install \ + git \ + wget + +# install miniforge +RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ + /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ + echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ + conda init && \ + rm -f /tmp/miniforge3.sh + +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py + +# create conda environment +RUN conda create --quiet -n multiqc python=3.9 pip +SHELL ["conda", "run", "-p", "/opt/conda/envs/multiqc", "/bin/bash", "-c"] + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +# install fastqc and multiqc +RUN conda install --quiet --yes -c bioconda fastqc +RUN conda install --quiet --yes -c bioconda multiqc + +# install qiita plugins +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip + +# install qp-multiqc plugin (lokal) +RUN git clone https://github.com/jlab/qp-multiqc.git +#COPY ./Images/qp-multiqc /qp-multiqc +WORKDIR qp-multiqc +RUN pip install -e . + +# optional: wenn du system-Zertifikate brauchst +RUN pip install pip-system-certs + +# plugin configuration and start script +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg +WORKDIR / +COPY start_qp-multiqc.sh . +RUN chmod 755 start_qp-multiqc.sh +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +# put in certificates +COPY Certificates /unshared_certificates +RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` +RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +# plugin setup +RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python3.9/site-packages/qiita_client/plugin.py +RUN chmod +x /qp-multiqc/scripts/configure_qp_multiqc +RUN /qp-multiqc/scripts/configure_qp_multiqc --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-multiqc/" /unshared_plugins/*.conf + +# start script +CMD ["./start_qp-multiqc.sh"] diff --git a/Images/qp-multiqc/start_qp-multiqc.sh b/Images/qp-multiqc/start_qp-multiqc.sh new file mode 100644 index 0000000..eb5fae3 --- /dev/null +++ b/Images/qp-multiqc/start_qp-multiqc.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +#!/bin/bash + +#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt +export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg +CONDA_DIR=/opt/conda +ENV_NAME=qp-multiqc + +# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) + +#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT + +#start_biom https://localhost:8383 register ignored +#start_biom http://qiita:8383 register ignored +#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py +cd / && python trigger.py multiqc start_qp_multiqc /qp-multiqc + +tail -f /dev/null \ No newline at end of file diff --git a/Makefile b/Makefile index 90927b7..d1462e6 100644 --- a/Makefile +++ b/Makefile @@ -94,6 +94,20 @@ plugin: Images/qtp-biom/trigger.py Certificates/ cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita touch .built_image_qiita +.built_image_qp-multiqc: Images/qp-multiqc/qp-multiqc.dockerfile Images/qp-multiqc/start_qp-multiqc.sh + tmpdir=$(TMPDIR) $(MAKE) plugin + cp $^ $(TMPDIR) + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + touch .built_image_`basename $< | cut -d "." -f 1` + +# .built_image_qp-multiqc: Images/qp-multiqc/qp-multiqc.dockerfile Images/qp-multiqc/start_qp-multiqc.sh +# tmpdir=$(TMPDIR) $(MAKE) plugin +# cp -r Images/qp-multiqc $(TMPDIR)/ +# mkdir -p $(TMPDIR)/Images/qtp-biom/ +# cp Images/qtp-biom/trigger.py $(TMPDIR)/Images/qtp-biom/ +# $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` +# touch .built_image_`basename $< | cut -d "." -f 1` + .built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) @@ -101,7 +115,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur .built_image_qp-qiime2 .built_image_qp-qiime2 .built_image_qtp-job-output-folder +images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur .built_image_qp-qiime2 .built_image_qp-qiime2 .built_image_qtp-job-output-folder .built_image_qp-multiqc environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env diff --git a/compose.yaml b/compose.yaml index dd53596..ed2084d 100644 --- a/compose.yaml +++ b/compose.yaml @@ -343,6 +343,26 @@ services: networks: - qiita-net + qp-multiqc: + image: local-qp-multiqc:latest + command: ['./start_qp-multiqc.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + environment: + # TODO: is there a more elegant way to obtain this path? + - REQUESTS_CA_BUNDLE=/opt/conda/envs/multiqc/lib/python3.9/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/multiqc/lib/python3.9/site-packages/certifi/cacert.pem + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + #depends_on: + #- qiita + networks: + - qiita-net + plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -375,7 +395,7 @@ services: qtp-job-output-folder: condition: service_started environment: - - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" + - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:qp-multiqc:" command: ['/startup_plugin_collector.sh'] networks: From e0258c02a0126e2419cf151bf18c5e9a68da0fac Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 28 May 2025 16:27:15 +0200 Subject: [PATCH 103/287] Revert "added qp-multiqc dependencys (Makefile, compose.yaml, Images/qp-multiqc)" This reverts commit 4bff551772f83f4a4a2433f4ea7c86be1eca4118. --- .gitignore | 1 - Images/plugin_collector/fix_test_db.py | 3 - Images/qp-multiqc/qp-multiqc.dockerfile | 74 ------------------------- Images/qp-multiqc/start_qp-multiqc.sh | 19 ------- Makefile | 16 +----- compose.yaml | 22 +------- 6 files changed, 2 insertions(+), 133 deletions(-) delete mode 100644 Images/qp-multiqc/qp-multiqc.dockerfile delete mode 100644 Images/qp-multiqc/start_qp-multiqc.sh diff --git a/.gitignore b/.gitignore index 63dd0ee..897a633 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ environments/*.env logs/* .built_image_* Certificates/* -src/ diff --git a/Images/plugin_collector/fix_test_db.py b/Images/plugin_collector/fix_test_db.py index bf1e383..7865708 100644 --- a/Images/plugin_collector/fix_test_db.py +++ b/Images/plugin_collector/fix_test_db.py @@ -33,9 +33,6 @@ SQL_get_softwareID_clientID = "SELECT software.software_id, oauth_software.client_id FROM qiita.software JOIN qiita.oauth_software ON qiita.software.software_id=qiita.oauth_software.software_id WHERE name='%s' AND version='%s';" % ( config['main']['name'], config['main']['version'] ) - - print(f" Plugin-Konfig: name='{config['main']['name']}', version='{config['main']['version']}'") - cursor.execute(SQL_get_softwareID_clientID) sql_result = cursor.fetchone() if sql_result is None: diff --git a/Images/qp-multiqc/qp-multiqc.dockerfile b/Images/qp-multiqc/qp-multiqc.dockerfile deleted file mode 100644 index d75fdfc..0000000 --- a/Images/qp-multiqc/qp-multiqc.dockerfile +++ /dev/null @@ -1,74 +0,0 @@ -# base image: ubuntu:24.04 -FROM ubuntu:24.04 - -ARG MINIFORGE_VERSION=24.1.2-0 - -# set environments -ENV CONDA_DIR=/opt/conda -ENV PATH=${CONDA_DIR}/bin:${PATH} - -# install system dependencies -RUN apt-get -y update -RUN apt-get -y --fix-missing install \ - git \ - wget - -# install miniforge -RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ - /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc && \ - conda init && \ - rm -f /tmp/miniforge3.sh - -# install tornado based trigger layer in base environment -RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py - -# create conda environment -RUN conda create --quiet -n multiqc python=3.9 pip -SHELL ["conda", "run", "-p", "/opt/conda/envs/multiqc", "/bin/bash", "-c"] - -ENV LC_ALL=C.UTF-8 -ENV LANG=C.UTF-8 - -# install fastqc and multiqc -RUN conda install --quiet --yes -c bioconda fastqc -RUN conda install --quiet --yes -c bioconda multiqc - -# install qiita plugins -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip - -# install qp-multiqc plugin (lokal) -RUN git clone https://github.com/jlab/qp-multiqc.git -#COPY ./Images/qp-multiqc /qp-multiqc -WORKDIR qp-multiqc -RUN pip install -e . - -# optional: wenn du system-Zertifikate brauchst -RUN pip install pip-system-certs - -# plugin configuration and start script -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg -WORKDIR / -COPY start_qp-multiqc.sh . -RUN chmod 755 start_qp-multiqc.sh -RUN mkdir -p /unshared_plugins -ENV QIITA_PLUGINS_DIR=/unshared_plugins/ - -# put in certificates -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` - -# plugin setup -RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python3.9/site-packages/qiita_client/plugin.py -RUN chmod +x /qp-multiqc/scripts/configure_qp_multiqc -RUN /qp-multiqc/scripts/configure_qp_multiqc --env-script "true" --server-cert /unshared_certificates/stefan_server.crt -RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-multiqc/" /unshared_plugins/*.conf - -# start script -CMD ["./start_qp-multiqc.sh"] diff --git a/Images/qp-multiqc/start_qp-multiqc.sh b/Images/qp-multiqc/start_qp-multiqc.sh deleted file mode 100644 index eb5fae3..0000000 --- a/Images/qp-multiqc/start_qp-multiqc.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -#!/bin/bash - -#export QIITA_ROOTCA_CERT=/qiita/qiita_core/support_files/ci_server.crt -export QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg -CONDA_DIR=/opt/conda -ENV_NAME=qp-multiqc - -# Commented out because I wanted to jump onto the container to crawl into the code (it crashes during the start_biom step) - -#configure_biom --env-script "source /opt/conda/bin/activate ; conda activate qtp-biom" --server-cert $QIITA_ROOTCA_CERT - -#start_biom https://localhost:8383 register ignored -#start_biom http://qiita:8383 register ignored -#source $CONDA_DIR/etc/profile.d/conda.sh; conda activate $CONDA_DIR/envs/$ENV_NAME; cd / && python trigger.py -cd / && python trigger.py multiqc start_qp_multiqc /qp-multiqc - -tail -f /dev/null \ No newline at end of file diff --git a/Makefile b/Makefile index d1462e6..90927b7 100644 --- a/Makefile +++ b/Makefile @@ -94,20 +94,6 @@ plugin: Images/qtp-biom/trigger.py Certificates/ cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita touch .built_image_qiita -.built_image_qp-multiqc: Images/qp-multiqc/qp-multiqc.dockerfile Images/qp-multiqc/start_qp-multiqc.sh - tmpdir=$(TMPDIR) $(MAKE) plugin - cp $^ $(TMPDIR) - $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` - touch .built_image_`basename $< | cut -d "." -f 1` - -# .built_image_qp-multiqc: Images/qp-multiqc/qp-multiqc.dockerfile Images/qp-multiqc/start_qp-multiqc.sh -# tmpdir=$(TMPDIR) $(MAKE) plugin -# cp -r Images/qp-multiqc $(TMPDIR)/ -# mkdir -p $(TMPDIR)/Images/qtp-biom/ -# cp Images/qtp-biom/trigger.py $(TMPDIR)/Images/qtp-biom/ -# $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` -# touch .built_image_`basename $< | cut -d "." -f 1` - .built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) @@ -115,7 +101,7 @@ plugin: Images/qtp-biom/trigger.py Certificates/ $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector -images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur .built_image_qp-qiime2 .built_image_qp-qiime2 .built_image_qtp-job-output-folder .built_image_qp-multiqc +images: .built_image_qtp-biom .built_image_nginx .built_image_qiita .built_image_plugin_collector .built_image_qtp-sequencing .built_image_qp-target-gene .built_image_qtp-visualization .built_image_qtp-diversity .built_image_qp-deblur .built_image_qp-qiime2 .built_image_qp-qiime2 .built_image_qtp-job-output-folder environments/qiita_db.env: environments/qiita_db.env.example cp environments/qiita_db.env.example environments/qiita_db.env diff --git a/compose.yaml b/compose.yaml index ed2084d..dd53596 100644 --- a/compose.yaml +++ b/compose.yaml @@ -343,26 +343,6 @@ services: networks: - qiita-net - qp-multiqc: - image: local-qp-multiqc:latest - command: ['./start_qp-multiqc.sh'] - # network_mode: host - # stdin_open: true - # tty: true - restart: no - volumes: - - qiita-data:/qiita - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? - environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/multiqc/lib/python3.9/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/multiqc/lib/python3.9/site-packages/certifi/cacert.pem - - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - #depends_on: - #- qiita - networks: - - qiita-net - plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume @@ -395,7 +375,7 @@ services: qtp-job-output-folder: condition: service_started environment: - - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:qp-multiqc:" + - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" command: ['/startup_plugin_collector.sh'] networks: From 478fec6e45a8bdd27c3b182b9d16e767cf7c9664 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 4 Jul 2025 11:30:14 +0200 Subject: [PATCH 104/287] fix local time zone information in qiime2 container as it otherwise fails executing any qiime python command --- compose.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/compose.yaml b/compose.yaml index dd53596..dcbdd16 100644 --- a/compose.yaml +++ b/compose.yaml @@ -321,6 +321,7 @@ services: - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - TZ=Europe/Berlin # this is important to avoid a local timezone error! See https://forum.qiime2.org/t/qiime2-timezone-error/17410 networks: - qiita-net From f6a91cb3f80f079067258ec70285d8fbea92883d Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 4 Jul 2025 16:16:22 +0200 Subject: [PATCH 105/287] fix git repo warning --- Images/qiita/qiita.dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index 2a69b06..79f126c 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -80,4 +80,7 @@ COPY drop_workflows.py /drop_workflows.py # install aspera client for ENA submission RUN conda install hcc::aspera-cli +# something is wired with permissions of the git repo?! +RUN git config --global --add safe.directory /qiita + # CMD ["conda", "run", "-n", "qiita"] From 566dd6ed74e42061f9d6d89784ae2a83c5e8b7a9 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 4 Jul 2025 16:18:17 +0200 Subject: [PATCH 106/287] update qiime2 in qtp-siualization --- Images/qtp-visualization/qtp-visualization.dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile index 799f10a..1e917d0 100644 --- a/Images/qtp-visualization/qtp-visualization.dockerfile +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -28,11 +28,11 @@ RUN pip install -U pip RUN conda install tornado COPY trigger.py /trigger.py -# Download qiime2 yaml -RUN wget -q https://data.qiime2.org/distro/core/qiime2-2019.10-py36-linux-conda.yml +# Download qiime2 yaml (make sure to use a qiime2 version that is able to visualize qiime artifacts of the correct version) +RUN wget --quiet https://data.qiime2.org/distro/core/qiime2-2023.5-py38-linux-conda.yml # Create conda env -RUN conda env create --name qtp-visualization -y --file qiime2-2019.10-py36-linux-conda.yml +RUN conda env create --name qtp-visualization -y --file qiime2-2023.5-py38-linux-conda.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-visualization", "/bin/bash", "-c"] From 111d80f21a4e4192314b4b398db2c440c7ed8c24 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 4 Jul 2025 16:19:15 +0200 Subject: [PATCH 107/287] update python version --- compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compose.yaml b/compose.yaml index dcbdd16..142a3ec 100644 --- a/compose.yaml +++ b/compose.yaml @@ -259,8 +259,8 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.8/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: From adc97887ef6a2b046fd50cd9fe2aee74580d65e5 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 09:48:31 +0200 Subject: [PATCH 108/287] make downward compatible for deblur using py3.5 --- Images/qtp-biom/trigger.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Images/qtp-biom/trigger.py b/Images/qtp-biom/trigger.py index e8c9cfe..aec0f47 100644 --- a/Images/qtp-biom/trigger.py +++ b/Images/qtp-biom/trigger.py @@ -4,6 +4,7 @@ import subprocess from glob import glob import sys +import traceback conda_env_name = None plugin_start_script = None @@ -13,7 +14,7 @@ class RunCommandHandler(tornado.web.RequestHandler): def post(self): try: # JSON-Request-Daten lesen - data = json.loads(self.request.body) + data = json.loads(self.request.body.decode("utf-8")) qiita_worker_url = data.get('url') job_id = data.get('job_id') output_dir = data.get('output_dir') @@ -27,7 +28,7 @@ def post(self): # Systembefehl ausfuehren cmd = 'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s; %s/scripts/%s %s %s %s' % (conda_env_name, plugin_src_dir, plugin_start_script, qiita_worker_url, job_id, output_dir) - result = subprocess.run(cmd, shell=True, capture_output=True, text=True, executable='/bin/bash') + result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Antwort zurueckgeben self.write({ @@ -45,6 +46,7 @@ def post(self): plugin_name = f.split('_')[-1].replace('.sh', '') break print("Error in service '%s': %s" % (plugin_name, str(e)), file=sys.stderr) + traceback.print_exc() self.write({"error": str(e)}) class RunConfigHandler(tornado.web.RequestHandler): From 9f02c3473fd960c32695f7e521a07f5d5eea8693 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 15:20:31 +0200 Subject: [PATCH 109/287] also ignore newly designed "references" directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 897a633..7af62fb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ environments/*.env logs/* .built_image_* Certificates/* +references/* \ No newline at end of file From bb9b7820609098352e884ad6a893f668ca70042f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 15:29:42 +0200 Subject: [PATCH 110/287] updating qp-deblur: extra target to create reference + using non-conda trigger script --- Makefile | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 90927b7..4d2498b 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PODMAN_FLAGS = PODMAN_BIN = docker buildx CERTNAME=stefan OPENSSL=/bin/openssl +DIR_REFERENCES=references # docker compose prepends name of directory to containers TMPDIR := $(shell mktemp -d) @@ -28,7 +29,7 @@ Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/s # === end: create own certificates === # a general target, executed for each plugin -plugin: Images/qtp-biom/trigger.py Certificates/ +plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py Certificates/ cp -r $^ $(tmpdir)/ .built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh @@ -62,7 +63,15 @@ plugin: Images/qtp-biom/trigger.py Certificates/ $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qp-deblur: Images/qp-deblur/qp-deblur.dockerfile Images/qp-deblur/start_qp-deblur.sh +# download Silva and GG13.8 reference sets from bioconda fragment-insertion package, instead of storing these large files within the qp-deblur image ~1.3 GB +references/qp-deblur/reference-gg-raxml-bl.tre: + mkdir -p $(DIR_REFERENCES)/tmp_sepp $(DIR_REFERENCES)/qp-deblur + wget "https://anaconda.org/biocore/fragment-insertion/4.3.5/download/linux-64/fragment-insertion-4.3.5-py35_0.tar.bz2" -O $(DIR_REFERENCES)/tmp_sepp/fragment-insertion-4.3.5-py35_0.tar.bz2 + cd $(DIR_REFERENCES)/tmp_sepp && tar xjf fragment-insertion-4.3.5-py35_0.tar.bz2 + cp $(DIR_REFERENCES)/tmp_sepp/share/fragment-insertion/ref/* $(DIR_REFERENCES)/qp-deblur/ + rm -rf $(DIR_REFERENCES)/tmp_sepp/ + +.built_image_qp-deblur: Images/qp-deblur/qp-deblur.dockerfile Images/qp-deblur/start_qp-deblur.sh references/qp-deblur/reference-gg-raxml-bl.tre tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From c5e73b0e5dab91598f9587983aace7a190445d9b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 15:36:35 +0200 Subject: [PATCH 111/287] a version that ignores conda at all, for smaller plugin container --- Images/qp-deblur/trigger_noconda.py | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Images/qp-deblur/trigger_noconda.py diff --git a/Images/qp-deblur/trigger_noconda.py b/Images/qp-deblur/trigger_noconda.py new file mode 100644 index 0000000..00890aa --- /dev/null +++ b/Images/qp-deblur/trigger_noconda.py @@ -0,0 +1,70 @@ +import tornado.ioloop +import tornado.web +import json +import subprocess +from glob import glob +import sys +import traceback +import os + +plugin_start_script = None + +class RunCommandHandler(tornado.web.RequestHandler): + def post(self): + try: + # JSON-Request-Daten lesen + data = json.loads(self.request.body.decode("utf-8")) + qiita_worker_url = data.get('url') + job_id = data.get('job_id') + output_dir = data.get('output_dir') + + #command = data.get("command") + + if not qiita_worker_url or not job_id or not output_dir: + self.set_status(400) + self.write({"error": "Kein Befehl angegeben"}) + return + + # Systembefehl ausfuehren + cmd = '%s %s %s %s' % (plugin_start_script, qiita_worker_url, job_id, output_dir) + result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + # Antwort zurueckgeben + self.write({ + "stdout": result.stdout, + "stderr": result.stderr, + "returncode": result.returncode, + "cmd": cmd, + }) + + except Exception as e: + self.set_status(500) + # a hack to learn which docker service I am in + plugin_name = os.path.basename(plugin_start_script).replace('start_', '') + print("Error in service '%s': %s" % (plugin_name, str(e)), file=sys.stderr) + traceback.print_exc() + self.write({"error": str(e)}) + +class RunConfigHandler(tornado.web.RequestHandler): + def get(self): + try: + for fp_config in glob('/unshared_plugins/*.conf'): + with open(fp_config, 'r') as f: + self.write('\n'.join(f.readlines()) + '\n') + except Exception as e: + self.set_status(500) + self.write({"error": str(e)}) + +def make_app(): + return tornado.web.Application([ + (r"/run", RunCommandHandler), + (r"/config", RunConfigHandler), + ]) + +if __name__ == "__main__": + plugin_start_script = sys.argv[1] + + app = make_app() + app.listen(5000) # Server auf Port 5000 starten + print("Server laeuft auf http://localhost:5000", file=sys.stderr) + tornado.ioloop.IOLoop.current().start() From 48bb413727a0be90b8eb9a514ddfd50feef7fd7b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 15:37:06 +0200 Subject: [PATCH 112/287] adapt to small non-conda container --- Images/qp-deblur/start_qp-deblur.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qp-deblur/start_qp-deblur.sh b/Images/qp-deblur/start_qp-deblur.sh index a8b9bac..b2a90c6 100644 --- a/Images/qp-deblur/start_qp-deblur.sh +++ b/Images/qp-deblur/start_qp-deblur.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py deblur start_deblur /qp-deblur +cd / && python trigger.py start_deblur tail -f /dev/null From f8bb0d875a95b872a43625d777d6024ce0970f26 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 15:37:57 +0200 Subject: [PATCH 113/287] heavy changes to obtain a smaller docker image: using two-stage mechanism --- Images/qp-deblur/qp-deblur.dockerfile | 95 ++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 8376971..b6983b4 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -1,4 +1,7 @@ -FROM ubuntu:24.04 +# ========================== +# Stage 1: Build wheels +# ========================== +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 @@ -23,11 +26,6 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh -# install tornado based trigger layer in base environment -RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py - # Create conda env RUN conda create --quiet -n deblur python=3.5 pip libgfortran=3 # Make RUN commands use the new environment: @@ -37,23 +35,74 @@ SHELL ["conda", "run", "-p", "/opt/conda/envs/deblur", "/bin/bash", "-c"] ENV LC_ALL=C.UTF-8 ENV LANG=C.UTF-8 +RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py +RUN cd qiita_client && pip install --no-cache-dir . + RUN conda install --quiet --yes -c bioconda -c biocore "VSEARCH=2.7.0" MAFFT=7.310 SortMeRNA=2.0 fragment-insertion gcc RUN pip install -U pip RUN pip install numpy cython pandas RUN pip install scikit-bio==0.5.5 -#RUN conda install --quiet --yes -c conda-forge -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip -RUN git clone https://github.com/qiita-spots/qp-deblur.git -WORKDIR qp-deblur -RUN pip install -e . -RUN pip install pip-system-certs +RUN pip install -U pip pip-system-certs + +RUN git clone -b uncouplePlugins https://github.com/jlab/qp-deblur.git +RUN cd qp-deblur && pip install . + +RUN echo "scikit-bio==0.5.5" > req.txt && echo "-e /qp-deblur" >> req.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt + + +# ========================== +# Stage 2: Runtime +# ========================== +FROM python:3.5-slim +# ^^ 110 MB + +# deblur dependent binaries + necessary libraries: mafft, vsearch, sortmerna +COPY --from=builder /opt/conda/envs/deblur/bin/mafft /opt/conda/envs/deblur/bin/vsearch /opt/conda/envs/deblur/bin/indexdb_rna /opt/conda/envs/deblur/bin/sortmerna /usr/local/bin/ +# ^^ 113 MB +COPY --from=builder /opt/conda/envs/deblur/libexec/mafft /opt/conda/envs/deblur/libexec/mafft/ +# ^^ 122 MB +COPY --from=builder /opt/conda/envs/deblur/lib/libgomp.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 +# ^^ 123 MB + +# python package compile in build stage +COPY --from=builder /wheels /wheels +# ^^ 235 MB +RUN pip install --no-cache-dir /wheels/* \ + && rm -rf /usr/local/lib/python3.5/site-packages/biom/tests +# ^^ 612 MB + +COPY --from=builder /opt/conda/envs/deblur/bin/run-sepp.sh /opt/conda/envs/deblur/bin/seppJsonMerger.jar /opt/conda/envs/deblur/bin/hmm* /opt/conda/envs/deblur/bin/pplacer /opt/conda/envs/deblur/bin/guppy /usr/local/bin/ +# ^^ 633 MB + +# minimal Java Runtime Environment for SEPP's seppJsonMerger.jar +RUN mkdir -p /usr/share/man/man1 && \ + echo "deb [trusted=yes] http://archive.debian.org/debian buster main" > /etc/apt/sources.list && \ + echo "deb [trusted=yes] http://archive.debian.org/debian-security buster/updates main" >> /etc/apt/sources.list && \ + echo "deb [trusted=yes] http://archive.debian.org/debian buster-updates main" >> /etc/apt/sources.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends openjdk-11-jre-headless && \ + rm -rf /var/lib/apt/lists/* +# ^^ 841 MB + +# copy SEPP +COPY --from=builder /opt/conda/envs/deblur/share/fragment-insertion/sepp/run_sepp.py /opt/conda/envs/deblur/share/fragment-insertion/sepp/run_sepp.py +COPY --from=builder /opt/conda/envs/deblur/share/fragment-insertion/sepp/sepp /opt/conda/envs/deblur/share/fragment-insertion/sepp/sepp +COPY --from=builder /opt/conda/envs/deblur/share/fragment-insertion/sepp/dendropy /opt/conda/envs/deblur/share/fragment-insertion/sepp/dendropy +COPY --from=builder /opt/conda/envs/deblur/share/fragment-insertion/sepp/home.path /opt/conda/envs/deblur/share/fragment-insertion/sepp/home.path +COPY --from=builder /opt/conda/envs/deblur/share/fragment-insertion/sepp/.sepp/main.config /opt/conda/envs/deblur/share/fragment-insertion/sepp/.sepp/main.config +RUN sed -i "s|/opt/conda/envs/deblur/share/fragment-insertion/sepp/.sepp/bundled-v4.3.5/|/usr/local/bin/|g" /opt/conda/envs/deblur/share/fragment-insertion/sepp/.sepp/main.config +# ^^ 845 MB +# following step increases image size from by 1.3 GB!! Better mount as volume and "make" these files during Makefile execution +# COPY --from=builder /opt/conda/envs/deblur/share/fragment-insertion/ref/ /opt/conda/envs/deblur/share/fragment-insertion/ref/ -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg -WORKDIR / +# install tornado based trigger layer in base environment +RUN pip install -U --no-cache-dir tornado pip-system-certs +COPY trigger_noconda.py /trigger.py +# ^^ 848 MB COPY start_qp-deblur.sh . RUN chmod 755 start_qp-deblur.sh @@ -68,8 +117,18 @@ RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where()) RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python3.5/site-packages/qiita_client/plugin.py -RUN /qp-deblur/scripts/configure_deblur --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/configure_deblur +RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/start_deblur + +# use git branch instead of pypi version (stored via wheel) +COPY --from=builder /qiita_client /qiita_client +RUN cd qiita_client && pip install . + +RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert /unshared_certificates/stefan_server.crt --plugin-coupling filesystem RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf +# remove conda command from tigger.py +RUN sed -i "s|source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s;||" /trigger.py && sed -i "s|conda_env_name, ||" /trigger.py + CMD ["./start_qp-deblur.sh"] +# ^^ 848 MB \ No newline at end of file From 75e39439d3ea801a0445d13f826ca11d069ebb75 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 15:38:49 +0200 Subject: [PATCH 114/287] using small qp-deblur plugin image --- compose.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compose.yaml b/compose.yaml index dd53596..715b2ae 100644 --- a/compose.yaml +++ b/compose.yaml @@ -259,8 +259,8 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? environment: # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.6/site-packages/certifi/cacert.pem + - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.8/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: @@ -294,14 +294,12 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? - - ./src/qtp-biom:/qtp-biom:U + - ./references/qp-deblur:/opt/conda/envs/deblur/share/fragment-insertion/ref environment: # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem + - REQUESTS_CA_BUNDLE=/usr/local/lib/python3.5/site-packages/certifi/cacert.pem + - SSL_CERT_FILE=/usr/local/lib/python3.5/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -321,6 +319,7 @@ services: - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - TZ=Europe/Berlin # this is important to avoid a local timezone error! See https://forum.qiime2.org/t/qiime2-timezone-error/17410 networks: - qiita-net From 50e62a855f57e6b8b0e80c1b419dd60a357674fe Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 21 Aug 2025 15:40:59 +0200 Subject: [PATCH 115/287] be more general --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4d2498b..d30c985 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py Certifica touch .built_image_`basename $< | cut -d "." -f 1` # download Silva and GG13.8 reference sets from bioconda fragment-insertion package, instead of storing these large files within the qp-deblur image ~1.3 GB -references/qp-deblur/reference-gg-raxml-bl.tre: +$(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre: mkdir -p $(DIR_REFERENCES)/tmp_sepp $(DIR_REFERENCES)/qp-deblur wget "https://anaconda.org/biocore/fragment-insertion/4.3.5/download/linux-64/fragment-insertion-4.3.5-py35_0.tar.bz2" -O $(DIR_REFERENCES)/tmp_sepp/fragment-insertion-4.3.5-py35_0.tar.bz2 cd $(DIR_REFERENCES)/tmp_sepp && tar xjf fragment-insertion-4.3.5-py35_0.tar.bz2 From aa084796b78c33908ed157580859bb34ac20c39b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 09:46:31 +0200 Subject: [PATCH 116/287] in the future, certificate files shall be mounted directly into containers to avoid having differing content and then SSL errors --- Images/plugin_collector/plugin_collector.dockerfile | 2 -- Images/plugin_collector/startup_plugin_collector.sh | 5 ----- 2 files changed, 7 deletions(-) diff --git a/Images/plugin_collector/plugin_collector.dockerfile b/Images/plugin_collector/plugin_collector.dockerfile index 5bdf0b2..baecfdf 100644 --- a/Images/plugin_collector/plugin_collector.dockerfile +++ b/Images/plugin_collector/plugin_collector.dockerfile @@ -12,6 +12,4 @@ COPY fix_test_db.py /fix_test_db.py COPY startup_plugin_collector.sh /startup_plugin_collector.sh RUN chmod u+x /startup_plugin_collector.sh -COPY Certificates /unshared_certificates - CMD /startup_plugin_collector.sh \ No newline at end of file diff --git a/Images/plugin_collector/startup_plugin_collector.sh b/Images/plugin_collector/startup_plugin_collector.sh index 3996854..8208fd2 100644 --- a/Images/plugin_collector/startup_plugin_collector.sh +++ b/Images/plugin_collector/startup_plugin_collector.sh @@ -1,10 +1,5 @@ #!/bin/bash -# copy certificates into shared volume, if not present there already -for f in `find /unshared_certificates -type f -name "*" | xargs`; do - test -f /qiita_certificates/`basename $f` || cp -v $f /qiita_certificates/`basename $f`; -done - # it seems to be necessary to give the plugin container some lead time # TODO: this might be more appropriately be addressed with healthchecks in the compose file sleep 3 From 3d0ea3171baee8906529faa0818e4d9724898efd Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 09:47:57 +0200 Subject: [PATCH 117/287] point to a predictable *.pem file, which will be mounted to container to avoid differing content --- Images/qp-deblur/qp-deblur.dockerfile | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 8376971..95abb0e 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -50,9 +50,6 @@ WORKDIR qp-deblur RUN pip install -e . RUN pip install pip-system-certs -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg - WORKDIR / COPY start_qp-deblur.sh . @@ -62,14 +59,15 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +#RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python3.5/site-packages/qiita_client/plugin.py -RUN /qp-deblur/scripts/configure_deblur --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qp-deblur/scripts/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf CMD ["./start_qp-deblur.sh"] From 1db96baa3a05f1877118230a996408a1d40a4d69 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 10:11:05 +0200 Subject: [PATCH 118/287] mount certificat files from host to container to avoid having different file versions --- Images/qp-qiime2/qp-qiime2.dockerfile | 10 +++++----- Images/qp-target-gene/qp-target-gene.dockerfile | 10 +++++----- Images/qtp-biom/qtp-biom.dockerfile | 10 +++++----- Images/qtp-diversity/qtp-diversity.dockerfile | 10 +++++----- .../qtp-job-output-folder.dockerfile | 10 +++++----- Images/qtp-sequencing/qtp-sequencing.dockerfile | 10 +++++----- Images/qtp-visualization/qtp-visualization.dockerfile | 10 +++++----- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Images/qp-qiime2/qp-qiime2.dockerfile b/Images/qp-qiime2/qp-qiime2.dockerfile index fcce068..3a63ce5 100644 --- a/Images/qp-qiime2/qp-qiime2.dockerfile +++ b/Images/qp-qiime2/qp-qiime2.dockerfile @@ -72,16 +72,16 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN chmod u+x /qp-qiime2/scripts/configure_qiime2 /qp-qiime2/scripts/start_qiime2 ENV QP_QIIME2_DBS=/databases ENV QP_QIIME2_FILTER_QZA=/filtering/ -RUN /qp-qiime2/scripts/configure_qiime2 --env-script 'true' --server-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qp-qiime2/scripts/configure_qiime2 --env-script 'true' --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-qiime2/" /unshared_plugins/*.conf CMD ["./start_qp-qiime2.sh"] diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index 20beaef..ddb2309 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -60,14 +60,14 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python2.7/site-packages/qiita_client/plugin.py -RUN /qp-target-gene/scripts/configure_target_gene --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qp-target-gene/scripts/configure_target_gene --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-target-gene/" /unshared_plugins/*.conf CMD ["./start_qp-target-gene.sh"] diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 460b19e..70ba865 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -64,13 +64,13 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf CMD ["./start_qtp-biom.sh"] diff --git a/Images/qtp-diversity/qtp-diversity.dockerfile b/Images/qtp-diversity/qtp-diversity.dockerfile index 098a481..1445123 100644 --- a/Images/qtp-diversity/qtp-diversity.dockerfile +++ b/Images/qtp-diversity/qtp-diversity.dockerfile @@ -59,14 +59,14 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN chmod u+x /qtp-diversity/scripts/configure_diversity_types /qtp-diversity/scripts/start_diversity_types -RUN /qtp-diversity/scripts/configure_diversity_types --env-script "true" --ca-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qtp-diversity/scripts/configure_diversity_types --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-diversity/" /unshared_plugins/*.conf CMD ["./start_qtp-diversity.sh"] diff --git a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile index eccff6e..a4ee767 100644 --- a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile +++ b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile @@ -53,14 +53,14 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN chmod u+x /qtp-job-output-folder/scripts/configure_qtp_job_output_folder /qtp-job-output-folder/scripts/start_qtp_job_output_folder -RUN /qtp-job-output-folder/scripts/configure_qtp_job_output_folder --env-script "true" --ca-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qtp-job-output-folder/scripts/configure_qtp_job_output_folder --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-job-output-folder/" /unshared_plugins/*.conf CMD ["./start_qtp-job-output-folder.sh"] diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index 5985300..a7f6750 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -55,13 +55,13 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN /qtp-sequencing/scripts/configure_qtp_sequencing --env-script "true" --ca-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qtp-sequencing/scripts/configure_qtp_sequencing --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-sequencing/" /unshared_plugins/*.conf #CMD ["conda", "run", "-n", "qtp-sequencing", "./start_qtp-sequencing.sh"] diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile index 1e917d0..f66612d 100644 --- a/Images/qtp-visualization/qtp-visualization.dockerfile +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -61,14 +61,14 @@ RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY Certificates /unshared_certificates -RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt RUN chmod u+x /qtp-visualization/scripts/configure_visualization_types /qtp-visualization/scripts/start_visualization_types -RUN /qtp-visualization/scripts/configure_visualization_types --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /qtp-visualization/scripts/configure_visualization_types --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-visualization/" /unshared_plugins/*.conf CMD ["./start_qtp-visualization.sh"] From 5ed449203f913b313f19e65febb9f3edf2a46354 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 10:11:40 +0200 Subject: [PATCH 119/287] keep certificat creation constand across multiple builds --- Makefile | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 90927b7..c50dfc6 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PODMAN_FLAGS = PODMAN_BIN = docker buildx CERTNAME=stefan OPENSSL=/bin/openssl +DIR_REFERENCES=references # docker compose prepends name of directory to containers TMPDIR := $(shell mktemp -d) @@ -9,26 +10,28 @@ ifeq ($(origin tmpdir), undefined) tmpdir = $(TMPDIR) endif -Certificates/: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/stefan_cert.conf +$(DIR_REFERENCES)/qiita_server_certificates: Images/plugin_collector/stefan_csr.conf Images/plugin_collector/stefan_cert.conf # === create own certificates === - mkdir -p Certificates/ + mkdir -p $@ # Generate a new root CA private key and certificate - cd $@/ && $(OPENSSL) req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=tinqiita-nginx-1/C=DE/L=Giessen" -keyout $(CERTNAME)_rootca.key -out $(CERTNAME)_rootca.crt + cd $@ && $(OPENSSL) req -x509 -sha256 -days 356 -nodes -newkey rsa:2048 -subj "/CN=tinqiita-nginx-1/C=DE/L=Giessen" -keyout $(CERTNAME)_rootca.key -out $(CERTNAME)_rootca.crt # Generate a new server private key - cd $@/ && $(OPENSSL) genrsa -out $(CERTNAME)_server.key 2048 + cd $@ && $(OPENSSL) genrsa -out $(CERTNAME)_server.key 2048 # Copy the following to a new file named csr.conf and modify to suit your needs # Copy the following to a new file named cert.conf and modify to suit your needs # Nils: alt_names is the important aspect. Make entries for all valid hostnames with which services shall be addressed for f in `echo "$^"`; do cat $$f > $@/`basename $$f`; done #cp $^ $@/ # Generate a certificate signing request - cd $@/ && $(OPENSSL) req -new -key $(CERTNAME)_server.key -out $(CERTNAME)_server.csr -config $(CERTNAME)_csr.conf + cd $@ && $(OPENSSL) req -new -key $(CERTNAME)_server.key -out $(CERTNAME)_server.csr -config $(CERTNAME)_csr.conf # Generate a new signed server.crt to use with your server.key - cd $@/ && $(OPENSSL) x509 -req -in $(CERTNAME)_server.csr -CA $(CERTNAME)_rootca.crt -CAkey $(CERTNAME)_rootca.key -CAcreateserial -out $(CERTNAME)_server.crt -days 365 -sha256 -extfile $(CERTNAME)_cert.conf + cd $@ && $(OPENSSL) x509 -req -in $(CERTNAME)_server.csr -CA $(CERTNAME)_rootca.crt -CAkey $(CERTNAME)_rootca.key -CAcreateserial -out $(CERTNAME)_server.crt -days 365 -sha256 -extfile $(CERTNAME)_cert.conf + # concat rootca and server certificates into one file + cd $@ && cat $(CERTNAME)_rootca.crt $(CERTNAME)_server.crt > qiita_server_certificates.pem # === end: create own certificates === # a general target, executed for each plugin -plugin: Images/qtp-biom/trigger.py Certificates/ +plugin: Images/qtp-biom/trigger.py $(DIR_REFERENCES)/qiita_server_certificates cp -r $^ $(tmpdir)/ .built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh @@ -97,7 +100,6 @@ plugin: Images/qtp-biom/trigger.py Certificates/ .built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) - cp -r Certificates/ $(tmpdir)/ $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-plugin_collector touch .built_image_plugin_collector @@ -114,7 +116,7 @@ config: environments/qiita_db.env environments/qiita.env make clean: rm .built_image_* - rm -rf Certificates + rm -rf $(DIR_REFERENCES) rm -rf /var/lib/docker/volumes/tinqiita_server-certificates/_data/* rm -rf /var/lib/docker/volumes/tinqiita_server-plugin-configs/_data/* From f194f7464e4e62bfe63722b67cff345e3ad0a825 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 10:13:48 +0200 Subject: [PATCH 120/287] distributing the SAME certificat files via mounts to the multiple container --- compose.yaml | 58 ++++++++++++---------------------------------------- 1 file changed, 13 insertions(+), 45 deletions(-) diff --git a/compose.yaml b/compose.yaml index 142a3ec..f7a88fe 100644 --- a/compose.yaml +++ b/compose.yaml @@ -70,7 +70,7 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins - - server-certificates:/qiita_certificates + - ./references/qiita_server_certificates:/qiita_certificates # - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh networks: - qiita-net @@ -110,7 +110,7 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins - - server-certificates:/qiita_certificates + - ./references/qiita_server_certificates:/qiita_certificates - ./src/qiita:/qiita:U # - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh networks: @@ -185,7 +185,7 @@ services: #- ./logs/nginx_error.log:/logs/nginx_error.log - ./logs:/logs - ./Images/nginx/nginx_qiita.conf:/qiita_configuration/nginx_qiita.conf - - server-certificates:/qiita_certificates + - ./references/qiita_server_certificates:/qiita_certificates networks: - qiita-net @@ -198,14 +198,10 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./references/qiita_server_certificates:/qiita_server_certificates - ./src/qtp-biom:/qtp-biom:U environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qtp-biom/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -218,13 +214,9 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./references/qiita_server_certificates:/qiita_server_certificates environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qtp-sequencing/lib/python3.9/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -237,13 +229,9 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./references/qiita_server_certificates:/qiita_server_certificates environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qp-target-gene/lib/python2.7/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -256,13 +244,9 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./references/qiita_server_certificates:/qiita_server_certificates environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-visualization/lib/python3.8/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qtp-visualization/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -275,13 +259,9 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./references/qiita_server_certificates:/qiita_server_certificates environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -294,14 +274,10 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? - - ./src/qtp-biom:/qtp-biom:U + - ./references/qiita_server_certificates:/qiita_server_certificates + #- ./src/qtp-biom:/qtp-biom:U environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/deblur/lib/python3.5/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -314,13 +290,9 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./references/qiita_server_certificates:/qiita_server_certificates environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qiime2/lib/python3.8/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg - TZ=Europe/Berlin # this is important to avoid a local timezone error! See https://forum.qiime2.org/t/qiime2-timezone-error/17410 networks: - qiita-net @@ -334,13 +306,9 @@ services: restart: no volumes: - qiita-data:/qiita_data - - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r # TODO: do we really want to expose server settings to the plugin? + - ./references/qiita_server_certificates:/qiita_server_certificates environment: - # TODO: is there a more elegant way to obtain this path? - - REQUESTS_CA_BUNDLE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem - - SSL_CERT_FILE=/opt/conda/envs/qtp-job-output-folder/lib/python3.6/site-packages/certifi/cacert.pem - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg networks: - qiita-net @@ -355,7 +323,7 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - server-plugin-configs:/qiita_plugins - qiita-data:/qiita_data - - server-certificates:/qiita_certificates + # - server-certificates:/qiita_certificates depends_on: qiita-initialize-db: condition: service_completed_successfully From f31769e516b365d46bd922919f44825665fa2413 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 10:15:45 +0200 Subject: [PATCH 121/287] remove unneccessary volume --- compose.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/compose.yaml b/compose.yaml index f7a88fe..1af06e5 100644 --- a/compose.yaml +++ b/compose.yaml @@ -323,7 +323,6 @@ services: - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - server-plugin-configs:/qiita_plugins - qiita-data:/qiita_data - # - server-certificates:/qiita_certificates depends_on: qiita-initialize-db: condition: service_completed_successfully @@ -359,4 +358,3 @@ volumes: #~ name: keycloak-postgres-data qiita-data: server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files - server-certificates: # server one copy of qiita server (master and workers) certificate files. If not in volume, "plugin_collector" should copy them there From 02977106513abd91f94710b13867000dbe53d4a4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 11:24:05 +0200 Subject: [PATCH 122/287] merge --- Images/qtp-biom/qtp-biom.dockerfile | 98 +++++++++++++++++++++++------ Makefile | 2 +- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 70ba865..7e47df8 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -1,4 +1,7 @@ -FROM ubuntu:24.04 +# ========================== +# Stage 1: Build wheels +# ========================== +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 @@ -27,11 +30,6 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh -# install tornado based trigger layer in base environment -RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py - # Download qtp-biom yaml RUN wget https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml @@ -41,24 +39,41 @@ RUN conda env create --quiet -n qtp-biom --file qiime2-2022.11-py38-linux-conda. # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] -RUN pip install -U pip -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +WORKDIR / +RUN git clone https://github.com/qiita-spots/qiita_client.git +WORKDIR qiita_client +RUN pip install . + +WORKDIR / +RUN git clone https://github.com/qiita-spots/qiita-files.git +WORKDIR qiita-files +RUN pip install . + +WORKDIR / RUN git clone https://github.com/qiita-spots/qtp-biom.git WORKDIR qtp-biom +RUN sed -i "s|, 'qiime2', |, |" setup.py +RUN sed -i "s|'qiita-files @ https://github.com/qiita-spots/'||" setup.py +RUN sed -i "s|'qiita-files/archive/master.zip',||" setup.py +RUN sed -i "s|'qiita_client @ https://github.com/qiita-spots/'||" setup.py +RUN sed -i "s|'qiita_client/archive/master.zip'||" setup.py +RUN sed -i "s|^import qiime2$|import qiime2.metadata|" qtp_biom/summary.py + RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -RUN conda install tornado -COPY trigger.py /trigger.py - -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg -WORKDIR / - -COPY start_qtp-biom.sh . -RUN chmod 755 start_qtp-biom.sh +RUN echo "-e /qiita_client" > req.txt +RUN echo "-e /qiita-files" >> req.txt +RUN echo "-e /qtp-biom" >> req.txt +RUN echo "pyyaml" >> req.txt +RUN echo "psutil" >> req.txt +RUN echo "flufl.lock" >> req.txt +RUN echo "decorator" >> req.txt +RUN echo "bibtexparser" >> req.txt +RUN echo "tzlocal" >> req.txt +RUN echo "dill" >> req.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ @@ -72,5 +87,50 @@ ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf +RUN sed -i "s|self._verify = ca_cert|self._verify = False|" /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiita_client/qiita_client.py + +# ========================== +# Stage 2: Runtime +# ========================== +FROM python:3.8-slim + +# python package compile in build stage +COPY --from=builder /wheels /wheels +# ^^ ?? MB + +RUN pip install --no-cache-dir /wheels/* + +#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2 /usr/local/lib/python3.8/site-packages/qiime2 +#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2-2022.11.1-py3.8.egg-info /usr/local/lib/python3.8/site-packages/ +COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/ +COPY --from=builder /opt/conda/envs/qtp-biom/lib/libopenblasp-r0.3.21.so /usr/local/lib/libopenblasp-r0.3.21.so +COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgfortran.so.5.0.0 /usr/local/lib/libgfortran.so.5 +COPY --from=builder /opt/conda/envs/qtp-biom/lib/libquadmath.so.0.0.0 /usr/local/lib/libquadmath.so.0 + +RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libcblas.so.3 +RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libblas.so.3 +RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapack.so.3 +RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapacke.so.3 + +# # RUN pip install -U pip +# # RUN conda install tornado +# # COPY trigger.py /trigger.py + + +# # COPY start_qtp-biom.sh . +# # RUN chmod 755 start_qtp-biom.sh + +# # RUN mkdir -p /unshared_plugins +# # ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +# # ## Export cert and config filepaths +# # COPY Certificates /unshared_certificates +# # RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust +# # RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` +# # RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` + +# # #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +# # RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert /unshared_certificates/stefan_server.crt +# # RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf -CMD ["./start_qtp-biom.sh"] +# # CMD ["./start_qtp-biom.sh"] diff --git a/Makefile b/Makefile index fe94c73..abb387f 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF test -d src/qtp-biom || git clone https://github.com/qiita-spots/qtp-biom.git src/qtp-biom tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) - $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t small-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` .built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh From 0e8cfe288d04bfef623a5cbcab106b192e6c719e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:21:44 +0200 Subject: [PATCH 123/287] adding patches for multistage qp-deblur build --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index abb387f..da6a409 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ $(DIR_REFERENCES)/qiita_server_certificates: Images/plugin_collector/stefan_csr. plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REFERENCES)/qiita_server_certificates cp -r $^ $(tmpdir)/ -.built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh +.built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh Images/qtp-biom/_visualizer.py.patch Images/qtp-biom/summary.py.patch test -d src/qtp-biom || git clone https://github.com/qiita-spots/qtp-biom.git src/qtp-biom tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) @@ -73,7 +73,7 @@ $(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre: cp $(DIR_REFERENCES)/tmp_sepp/share/fragment-insertion/ref/* $(DIR_REFERENCES)/qp-deblur/ rm -rf $(DIR_REFERENCES)/tmp_sepp/ -.built_image_qp-deblur: Images/qp-deblur/qp-deblur.dockerfile Images/qp-deblur/start_qp-deblur.sh references/qp-deblur/reference-gg-raxml-bl.tre +.built_image_qp-deblur: Images/qp-deblur/qp-deblur.dockerfile Images/qp-deblur/start_qp-deblur.sh $(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From 7764c3f050a4c092801515684fd5d421e62181e8 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:22:50 +0200 Subject: [PATCH 124/287] adding a version to the dockerfile --- Images/qp-deblur/qp-deblur.dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 2515590..a33261d 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.08.22 + # ========================== # Stage 1: Build wheels # ========================== From fe5420fd4dd52d725d3e000b95050cd54f0c23fa Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:23:07 +0200 Subject: [PATCH 125/287] in the middle of shrinking the image --- Images/qtp-biom/qtp-biom.dockerfile | 158 ++++++++++++++++++++++++---- 1 file changed, 137 insertions(+), 21 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 7e47df8..27d8f72 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.08.22 + # ========================== # Stage 1: Build wheels # ========================== @@ -51,7 +53,7 @@ RUN pip install . WORKDIR / RUN git clone https://github.com/qiita-spots/qtp-biom.git -WORKDIR qtp-biom +WORKDIR /qtp-biom RUN sed -i "s|, 'qiime2', |, |" setup.py RUN sed -i "s|'qiita-files @ https://github.com/qiita-spots/'||" setup.py RUN sed -i "s|'qiita-files/archive/master.zip',||" setup.py @@ -66,13 +68,17 @@ RUN pip install pip-system-certs RUN echo "-e /qiita_client" > req.txt RUN echo "-e /qiita-files" >> req.txt RUN echo "-e /qtp-biom" >> req.txt -RUN echo "pyyaml" >> req.txt -RUN echo "psutil" >> req.txt -RUN echo "flufl.lock" >> req.txt -RUN echo "decorator" >> req.txt -RUN echo "bibtexparser" >> req.txt -RUN echo "tzlocal" >> req.txt -RUN echo "dill" >> req.txt +RUN echo "scikit-bio" >> req.txt +RUN echo "bp" >> req.txt +# RUN echo "flufl.lock" >> req.txt +# RUN echo "decorator" >> req.txt +# RUN echo "bibtexparser" >> req.txt +# RUN echo "tzlocal" >> req.txt +# RUN echo "dill" >> req.txt +# RUN echo "charset_normalizer==2.1.1" >> req.txt +RUN echo "biom-format" >> req.txt +RUN echo "seaborn" >> req.txt +RUN echo "jinja2" >> req.txt RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt RUN mkdir -p /unshared_plugins @@ -80,8 +86,8 @@ ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem -ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem -ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem +# ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +# ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ @@ -89,6 +95,11 @@ RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qi RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf RUN sed -i "s|self._verify = ca_cert|self._verify = False|" /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiita_client/qiita_client.py +ARG Q2_RELEASE=2022.11 +WORKDIR /q2_src/ +RUN wget "https://github.com/qiime2/q2-feature-table/archive/refs/tags/${Q2_RELEASE}.0.tar.gz" -O - | tar -xzvf - +RUN wget "https://github.com/qiime2/q2templates/archive/refs/tags/${Q2_RELEASE}.0.tar.gz" -O - | tar -xzvf - + # ========================== # Stage 2: Runtime # ========================== @@ -98,21 +109,113 @@ FROM python:3.8-slim COPY --from=builder /wheels /wheels # ^^ ?? MB + RUN pip install --no-cache-dir /wheels/* +ARG Q2_RELEASE=2022.11 + +COPY --from=builder /q2_src/q2-feature-table-${Q2_RELEASE}.0/q2_feature_table/_summarize /q2summarize/ +COPY --from=builder /q2_src/q2templates-${Q2_RELEASE}.0/q2templates/util.py /q2summarize/util.py +COPY --from=builder /q2_src/q2templates-${Q2_RELEASE}.0/q2templates/_templates.py /q2summarize/_templates.py +COPY --from=builder /q2_src/q2templates-${Q2_RELEASE}.0/q2templates/templates /q2summarize/templates/ +RUN sed -i "s|from .util import|import sys; sys.path.append('/'); from q2summarize.util import|" /q2summarize/_templates.py +RUN sed -i "s|pkg_resources.resource_filename('q2templates', 'templates')|'/q2summarize/templates/'|" /q2summarize/_templates.py +RUN sed -i "s|pd.option_context('display.max_colwidth', -1)|pd.option_context('display.max_colwidth', None)|" /q2summarize/util.py +RUN sed -i "s|sample_metadata = sample_metadata.filter_ids(|df = sample_metadata.loc[[s for s in sample_frequencies.index if s in sample_metadata.index], :]|" /q2summarize/_vega_spec.py +RUN sed -i "s|^[[:space:]]*sample_frequencies.index)||" /q2summarize/_vega_spec.py +RUN sed -i "s|df = sample_metadata.to_dataframe()||" /q2summarize/_vega_spec.py +RUN echo "from ._visualizer import summarize; __all__ = ['summarize']" > /q2summarize/__init__.py -#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2 /usr/local/lib/python3.8/site-packages/qiime2 -#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2-2022.11.1-py3.8.egg-info /usr/local/lib/python3.8/site-packages/ -COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/ -COPY --from=builder /opt/conda/envs/qtp-biom/lib/libopenblasp-r0.3.21.so /usr/local/lib/libopenblasp-r0.3.21.so -COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgfortran.so.5.0.0 /usr/local/lib/libgfortran.so.5 -COPY --from=builder /opt/conda/envs/qtp-biom/lib/libquadmath.so.0.0.0 /usr/local/lib/libquadmath.so.0 +RUN apt-get -y update +RUN apt-get -y --fix-missing install patch +WORKDIR /q2summarize +COPY _visualizer.py.patch /q2summarize/ +RUN patch -p1 _visualizer.py < _visualizer.py.patch +# # COPY --from=builder /q2_src/ /q2_all +COPY summary.py.patch /usr/local/lib/python3.8/site-packages/qtp_biom/ +WORKDIR /usr/local/lib/python3.8/site-packages/qtp_biom/ +RUN patch -p1 summary.py < summary.py.patch + +COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgomp.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 + +# install tornado based trigger layer in base environment +RUN pip install -U --no-cache-dir tornado pip-system-certs +COPY trigger_noconda.py /trigger.py +# ^^ 848 MB + +WORKDIR / -RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libcblas.so.3 -RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libblas.so.3 -RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapack.so.3 -RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapacke.so.3 +COPY start_qtp-biom.sh . +RUN chmod 755 start_qtp-biom.sh + + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +## Export cert and config filepaths +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem -# # RUN pip install -U pip +RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/configure_biom +RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/start_biom + +#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /usr/local/bin/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf + +CMD ["./start_qtp-biom.sh"] + +#/usr/local/lib/python3.8/site-packages/qtp_biom/summary.py + +# COPY 2_20250704-123139.txt /q2summarize/2_20250704-123139.txt +# COPY reference-hit.biom /q2summarize/ +# RUN mkdir -p /q2summarize/test.xxx +#/usr/local/lib/python3.8/site-packages + +#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2 /usr/local/lib/python3.8/site-packages/qiime2 +#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2-2022.11.1-py3.8.egg-info /usr/local/lib/python3.8/site-packages/ +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/ +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libopenblasp-r0.3.21.so /usr/local/lib/libopenblasp-r0.3.21.so +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgfortran.so.5.0.0 /usr/local/lib/libgfortran.so.5 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libquadmath.so.0.0.0 /usr/local/lib/libquadmath.so.0 + +# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libcblas.so.3 +# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libblas.so.3 +# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapack.so.3 +# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapacke.so.3 + +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libcrypto.so.1.1 /usr/local/lib/libcrypto.so.1.1 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libcurl.so.4.8.0 /usr/local/lib/libcurl.so.4 + +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libnghttp2.so.14.24.1 /usr/local/lib/libnghttp2.so.14 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libssh2.so.1.0.1 /usr/local/lib/libssh2.so.1 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libssh2.so.1.0.1 /usr/local/lib/libssh2.so.1 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libssl.so.1.1 /usr/local/lib/libssl.so.1.1 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libjpeg.so.9.5.0 /usr/local/lib/libjpeg.so.9 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libopenjp2.so.2.5.0 /usr/local/lib/libopenjp2.so.7 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libtiff.so.5.8.0 /usr/local/lib/libtiff.so.5 + +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libLerc.so.4 /usr/local/lib/libLerc.so.4 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libdeflate.so.0 /usr/local/lib/libdeflate.so.0 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libfreetype.so.6.18.3 /usr/local/lib/libfreetype.so.6 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/liblcms2.so.2.0.14 /usr/local/lib/iblcms2.so.2 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libwebp.so.7.1.5 /usr/local/lib/libwebp.so.7 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libwebpdemux.so.2.0.11 /usr/local/lib/libwebpdemux.so.2 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libwebpmux.so.3.0.10 /usr/local/lib/libwebpmux.so.3 +# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libxcb.so.1.1.0 /usr/local/lib/libxcb.so.1 + +# ENV REQUESTS_CA_BUNDLE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem +# ENV SSL_CERT_FILE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem +# RUN pip install biom-format + +#libwebp.so.7 libwebpmux.so.3 libwebpdemux.so.2 liblcms2.so.2 libfreetype.so.6 libxcb.so.1 libwebp.so.7 libLerc.so.4 libdeflate.so.0 + +# WORKDIR /usr/local/lib/python3.8/site-packages/qtp_biom +# RUN echo 'python summary.py' > /root/.bash_history +# # # RUN pip install -U pip # # RUN conda install tornado # # COPY trigger.py /trigger.py @@ -134,3 +237,16 @@ RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapacke.so.3 # # RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf # # CMD ["./start_qtp-biom.sh"] + + + + + + + + +# export REQUESTS_CA_BUNDLE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem +# export SSL_CERT_FILE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem +# pip install biom-format seaborn jinja2 +# cd /_summarize && mkdir -p /test.xxx +# python _visualizer.py \ No newline at end of file From 3612fc71b4c49482386180f91544b7b86f36019e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:23:31 +0200 Subject: [PATCH 126/287] revert back to local --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index da6a409..0dd25ab 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF test -d src/qtp-biom || git clone https://github.com/qiita-spots/qtp-biom.git src/qtp-biom tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) - $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t small-`basename $< | cut -d "." -f 1` + $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` .built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh From 26fde7304c5366504cfd59a32cfea2ac086535c8 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:23:43 +0200 Subject: [PATCH 127/287] adding new files --- .github/workflows/buildContainer.yaml | 36 ++++++++ Images/qtp-biom/_visualizer.py.patch | 128 ++++++++++++++++++++++++++ Images/qtp-biom/summary.py.patch | 16 ++++ 3 files changed, 180 insertions(+) create mode 100644 .github/workflows/buildContainer.yaml create mode 100644 Images/qtp-biom/_visualizer.py.patch create mode 100644 Images/qtp-biom/summary.py.patch diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml new file mode 100644 index 0000000..e104913 --- /dev/null +++ b/.github/workflows/buildContainer.yaml @@ -0,0 +1,36 @@ +name: docker + +on: + push: + branches: + - 'main' + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Read version from file + id: vars + run: | + make -j .built_image_qp-deblur + VERSION=$(head -n 1 Images/qp-deblur/qp-deblur.dockerfile | cut -d ":" -f 2- | tr -d " ") + echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: true + file: Dockerfile + tags: ${{ vars.DOCKERHUB_USERNAME }}/tinqiita-qp-deblur:${{ env.IMAGE_TAG }} \ No newline at end of file diff --git a/Images/qtp-biom/_visualizer.py.patch b/Images/qtp-biom/_visualizer.py.patch new file mode 100644 index 0000000..a46b0e4 --- /dev/null +++ b/Images/qtp-biom/_visualizer.py.patch @@ -0,0 +1,128 @@ +--- _visualizer.py 2022-12-19 21:51:47.000000000 +0000 ++++ _visualizer.py 2025-08-22 12:24:22.603489318 +0000 +@@ -16,48 +16,50 @@ + import seaborn as sns + import matplotlib + import matplotlib.pyplot as plt +-from q2_types.feature_data import DNAIterator +-import q2templates +-import skbio +-import qiime2 ++# from q2_types.feature_data import DNAIterator ++# import q2templates ++# import skbio ++# import qiime2 + import json +-from ._vega_spec import vega_spec ++import sys; sys.path.append("/"); from q2summarize import util ++from q2summarize import _templates ++from q2summarize._vega_spec import vega_spec + + _blast_url_template = ("http://www.ncbi.nlm.nih.gov/BLAST/Blast.cgi?" + "ALIGNMENT_VIEW=Pairwise&PROGRAM=blastn&DATABASE" + "=nt&CMD=Put&QUERY=%s") + +-TEMPLATES = pkg_resources.resource_filename('q2_feature_table', '_summarize') ++TEMPLATES = '/q2summarize/' + + +-def tabulate_seqs(output_dir: str, data: DNAIterator) -> None: +- sequences = [] +- seq_lengths = [] +- with open(os.path.join(output_dir, 'sequences.fasta'), 'w') as fh: +- for sequence in data: +- skbio.io.write(sequence, format='fasta', into=fh) +- str_seq = str(sequence) +- seq_len = len(str_seq) +- sequences.append({'id': sequence.metadata['id'], +- 'len': seq_len, +- 'url': _blast_url_template % str_seq, +- 'seq': str_seq}) +- seq_lengths.append(seq_len) +- seq_len_stats = _compute_descriptive_stats(seq_lengths) +- _write_tsvs_of_descriptive_stats(seq_len_stats, output_dir) +- +- index = os.path.join(TEMPLATES, 'tabulate_seqs_assets', 'index.html') +- q2templates.render(index, output_dir, context={'data': sequences, +- 'stats': seq_len_stats}) +- +- js = os.path.join( +- TEMPLATES, 'tabulate_seqs_assets', 'js', 'tsorter.min.js') +- os.mkdir(os.path.join(output_dir, 'js')) +- shutil.copy(js, os.path.join(output_dir, 'js', 'tsorter.min.js')) ++# def tabulate_seqs(output_dir: str, data: DNAIterator) -> None: ++# sequences = [] ++# seq_lengths = [] ++# with open(os.path.join(output_dir, 'sequences.fasta'), 'w') as fh: ++# for sequence in data: ++# skbio.io.write(sequence, format='fasta', into=fh) ++# str_seq = str(sequence) ++# seq_len = len(str_seq) ++# sequences.append({'id': sequence.metadata['id'], ++# 'len': seq_len, ++# 'url': _blast_url_template % str_seq, ++# 'seq': str_seq}) ++# seq_lengths.append(seq_len) ++# seq_len_stats = _compute_descriptive_stats(seq_lengths) ++# _write_tsvs_of_descriptive_stats(seq_len_stats, output_dir) ++ ++# index = os.path.join(TEMPLATES, 'tabulate_seqs_assets', 'index.html') ++# q2templates.render(index, output_dir, context={'data': sequences, ++# 'stats': seq_len_stats}) ++ ++# js = os.path.join( ++# TEMPLATES, 'tabulate_seqs_assets', 'js', 'tsorter.min.js') ++# os.mkdir(os.path.join(output_dir, 'js')) ++# shutil.copy(js, os.path.join(output_dir, 'js', 'tsorter.min.js')) + + + def summarize(output_dir: str, table: biom.Table, +- sample_metadata: qiime2.Metadata = None) -> None: ++ sample_metadata: pd.DataFrame = None) -> None: + # this value is to limit the amount of memory used by seaborn.histplot, for + # more information see: https://github.com/mwaskom/seaborn/issues/2325 + MAX_BINS = 50 +@@ -115,10 +117,9 @@ + os.path.join(output_dir, 'feature-frequencies.pdf')) + feature_frequencies_ax.get_figure().savefig( + os.path.join(output_dir, 'feature-frequencies.png')) +- +- sample_summary_table = q2templates.df_to_html( ++ sample_summary_table = util.df_to_html( + sample_summary.apply('{:,}'.format).to_frame('Frequency')) +- feature_summary_table = q2templates.df_to_html( ++ feature_summary_table = util.df_to_html( + feature_summary.apply('{:,}'.format).to_frame('Frequency')) + + index = os.path.join(TEMPLATES, 'summarize_assets', 'index.html') +@@ -142,7 +143,7 @@ + .apply('{:,}'.format).to_frame('Frequency') + feature_frequencies['# of Samples Observed In'] = \ + pd.Series(feature_qualitative_data).astype(int).apply('{:,}'.format) +- feature_frequencies_table = q2templates.df_to_html(feature_frequencies) ++ feature_frequencies_table = util.df_to_html(feature_frequencies) + sample_frequency_template = os.path.join( + TEMPLATES, 'summarize_assets', 'sample-frequency-detail.html') + feature_frequency_template = os.path.join( +@@ -172,11 +173,11 @@ + )) + }) + context.update({'sample_frequencies_json': sample_frequencies_json}) +- q2templates.util.copy_assets(os.path.join(TEMPLATES, ++ util.copy_assets(os.path.join(TEMPLATES, + 'summarize_assets', + 'vega'), + output_dir) +- q2templates.render(templates, output_dir, context=context) ++ _templates.render(templates, output_dir, context=context) + + plt.close('all') + +@@ -280,3 +281,5 @@ + 'Median frequency', '3rd quartile', + 'Maximum frequency', 'Mean frequency']) + return summary, frequencies ++ ++# summarize("test.xxx", biom.load_table('reference-hit.biom'), pd.read_csv('2_20250704-123139.txt', sep="\t", index_col=0)) +\ No newline at end of file + diff --git a/Images/qtp-biom/summary.py.patch b/Images/qtp-biom/summary.py.patch new file mode 100644 index 0000000..097d39e --- /dev/null +++ b/Images/qtp-biom/summary.py.patch @@ -0,0 +1,16 @@ +--- summary.py 2025-08-22 12:49:53.018094323 +0000 ++++ summary2.py 2025-08-22 12:39:34.242874354 +0000 +@@ -12,8 +12,11 @@ + import pandas as pd + from tempfile import mkstemp + +-import qiime2.metadata +-from qiime2.plugins.feature_table.visualizers import summarize ++#import qiime2 ++#from qiime2.plugins.feature_table.visualizers import summarize ++import sys ++sys.path.append("/") ++from q2summarize import * + from skbio.tree import TreeNode + from biom import load_table + From bf27ca6702b2d5c37e58c47e1cf902facd6c92b4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:26:12 +0200 Subject: [PATCH 128/287] change branch --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index e104913..65bb868 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -3,7 +3,7 @@ name: docker on: push: branches: - - 'main' + - 'smaller_deblur' jobs: docker: From ad7f74906b6fe361471b8d362ceed1cc4dcbe7d0 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:29:10 +0200 Subject: [PATCH 129/287] don't make --- .github/workflows/buildContainer.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 65bb868..eaf0853 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -24,7 +24,6 @@ jobs: - name: Read version from file id: vars run: | - make -j .built_image_qp-deblur VERSION=$(head -n 1 Images/qp-deblur/qp-deblur.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - name: Build and push Docker image From 94f804de64031a018d749fed4e5596f4514e7e5b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:30:13 +0200 Subject: [PATCH 130/287] point to correct file --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index eaf0853..e86be89 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -31,5 +31,5 @@ jobs: with: context: . push: true - file: Dockerfile + file: Images/qp-deblur/qp-deblur.dockerfile tags: ${{ vars.DOCKERHUB_USERNAME }}/tinqiita-qp-deblur:${{ env.IMAGE_TAG }} \ No newline at end of file From a28fb1f9775f783e330c7c6d8095943ae815cb85 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:36:53 +0200 Subject: [PATCH 131/287] create dir for github action --- Images/qp-deblur/qp-deblur.dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index a33261d..5b2a21b 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -125,6 +125,7 @@ RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/start_deblur COPY --from=builder /qiita_client /qiita_client RUN cd qiita_client && pip install . +RUN mkdir -p /qiita_server_certificates/ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` --plugin-coupling filesystem RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf From 29b6bc5843e74e6de6a6f8a63147a2a74f4a05e1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:37:11 +0200 Subject: [PATCH 132/287] copy files into context --- .github/workflows/buildContainer.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index e86be89..fc40833 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -26,6 +26,9 @@ jobs: run: | VERSION=$(head -n 1 Images/qp-deblur/qp-deblur.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + cp Images/qp-deblur/start_qp-deblur.sh Images/qp-deblur/trigger_noconda.py . + mkdir -p qiita_server_certificates/ + echo "fake" > qiita_server_certificates/qiita_server_certificates.pem - name: Build and push Docker image uses: docker/build-push-action@v6 with: From 78fd7f541cd79bab8868617bd3bf2a2a478e8d55 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:53:06 +0200 Subject: [PATCH 133/287] migrate to no_conda trigger --- Images/qtp-biom/qtp-biom.dockerfile | 5 ++++- Images/qtp-biom/start_qtp-biom.sh | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 27d8f72..8cde9ab 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -93,7 +93,7 @@ COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certi COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf -RUN sed -i "s|self._verify = ca_cert|self._verify = False|" /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiita_client/qiita_client.py +#RUN sed -i "s|self._verify = ca_cert|self._verify = False|" /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiita_client/qiita_client.py ARG Q2_RELEASE=2022.11 WORKDIR /q2_src/ @@ -164,6 +164,9 @@ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN /usr/local/bin/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf +# remove conda command from tigger.py +RUN sed -i "s|source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s;||" /trigger.py && sed -i "s|conda_env_name, ||" /trigger.py + CMD ["./start_qtp-biom.sh"] #/usr/local/lib/python3.8/site-packages/qtp_biom/summary.py diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index 3ab12c4..dc62c7e 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py qtp-biom start_biom /qtp-biom +cd / && python trigger.py start_biom tail -f /dev/null From cc5320b7fa7539d38fedded19582bd8b23c0971a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 16:58:18 +0200 Subject: [PATCH 134/287] ensure use of correct branch for qiita_client --- Images/qp-deblur/qp-deblur.dockerfile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 5b2a21b..c701b82 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -37,9 +37,12 @@ SHELL ["conda", "run", "-p", "/opt/conda/envs/deblur", "/bin/bash", "-c"] ENV LC_ALL=C.UTF-8 ENV LANG=C.UTF-8 +WORKDIR / RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py -RUN cd qiita_client && pip install --no-cache-dir . +WORKDIR /qiita_client +RUN pip install --no-cache-dir . +WORKDIR / RUN conda install --quiet --yes -c bioconda -c biocore "VSEARCH=2.7.0" MAFFT=7.310 SortMeRNA=2.0 fragment-insertion gcc RUN pip install -U pip @@ -51,7 +54,10 @@ RUN pip install -U pip pip-system-certs RUN git clone -b uncouplePlugins https://github.com/jlab/qp-deblur.git RUN cd qp-deblur && pip install . -RUN echo "scikit-bio==0.5.5" > req.txt && echo "-e /qp-deblur" >> req.txt +RUN echo "scikit-bio==0.5.5" > req.txt && \ + echo "-e /qp-deblur" >> req.txt && \ + echo "-e /qiita_client" >> req.txt + RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt From dd776d5b2f0327564e2162c1f21c6e4e47a54db2 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 17:35:54 +0200 Subject: [PATCH 135/287] revert --- Images/qp-deblur/qp-deblur.dockerfile | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index c701b82..5b2a21b 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -37,12 +37,9 @@ SHELL ["conda", "run", "-p", "/opt/conda/envs/deblur", "/bin/bash", "-c"] ENV LC_ALL=C.UTF-8 ENV LANG=C.UTF-8 -WORKDIR / RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py -WORKDIR /qiita_client -RUN pip install --no-cache-dir . -WORKDIR / +RUN cd qiita_client && pip install --no-cache-dir . RUN conda install --quiet --yes -c bioconda -c biocore "VSEARCH=2.7.0" MAFFT=7.310 SortMeRNA=2.0 fragment-insertion gcc RUN pip install -U pip @@ -54,10 +51,7 @@ RUN pip install -U pip pip-system-certs RUN git clone -b uncouplePlugins https://github.com/jlab/qp-deblur.git RUN cd qp-deblur && pip install . -RUN echo "scikit-bio==0.5.5" > req.txt && \ - echo "-e /qp-deblur" >> req.txt && \ - echo "-e /qiita_client" >> req.txt - +RUN echo "scikit-bio==0.5.5" > req.txt && echo "-e /qp-deblur" >> req.txt RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt From a61ac3852f010cee0754504fbe330f3ecb54f95e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 20:32:22 +0200 Subject: [PATCH 136/287] leave some comments --- Images/qtp-biom/summary.py.patch | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Images/qtp-biom/summary.py.patch b/Images/qtp-biom/summary.py.patch index 097d39e..b87c57b 100644 --- a/Images/qtp-biom/summary.py.patch +++ b/Images/qtp-biom/summary.py.patch @@ -1,16 +1,33 @@ ---- summary.py 2025-08-22 12:49:53.018094323 +0000 -+++ summary2.py 2025-08-22 12:39:34.242874354 +0000 +--- /usr/local/lib/python3.8/site-packages/qtp_biom/summary.py 2025-08-22 13:16:35.397740791 +0000 ++++ /exchange/summary.py 2025-08-22 18:22:40.548488772 +0000 @@ -12,8 +12,11 @@ import pandas as pd from tempfile import mkstemp -import qiime2.metadata -from qiime2.plugins.feature_table.visualizers import summarize -+#import qiime2 -+#from qiime2.plugins.feature_table.visualizers import summarize ++# import qiime2.metadata ++# from qiime2.plugins.feature_table.visualizers import summarize +import sys +sys.path.append("/") -+from q2summarize import * ++from q2summarize import * # this is a stripped, patched version from the above but comes with way less q2 dependencies! from skbio.tree import TreeNode from biom import load_table +@@ -57,12 +60,12 @@ + df = pd.DataFrame.from_dict(metadata, orient='index') + df.to_csv(path, index_label='#SampleID', na_rep='', sep='\t', + encoding='utf-8') +- metadata = qiime2.Metadata.load(path) ++ metadata = df # orig: qiime2.Metadata.load(path) + remove(path) +- else: +- metadata = qiime2.Metadata.load(metadata) ++ # else: ++ # metadata = qiime2.Metadata.load(metadata) + +- table = qiime2.Artifact.import_data('FeatureTable[Frequency]', biom_fp) ++ table = load_table(biom_fp) # orig: qiime2.Artifact.import_data('FeatureTable[Frequency]', biom_fp) + + summary, = summarize(table=table, sample_metadata=metadata) + index_paths = summary.get_index_paths() From 9b467d6973e49ea07615f0e8350513d2426eec1b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 22 Aug 2025 20:32:38 +0200 Subject: [PATCH 137/287] patch with correct working dir --- Images/qtp-biom/qtp-biom.dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 8cde9ab..e9406e3 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -131,9 +131,9 @@ WORKDIR /q2summarize COPY _visualizer.py.patch /q2summarize/ RUN patch -p1 _visualizer.py < _visualizer.py.patch # # COPY --from=builder /q2_src/ /q2_all -COPY summary.py.patch /usr/local/lib/python3.8/site-packages/qtp_biom/ -WORKDIR /usr/local/lib/python3.8/site-packages/qtp_biom/ -RUN patch -p1 summary.py < summary.py.patch +COPY summary.py.patch /summary.py.patch +WORKDIR / +RUN patch -p0 < /summary.py.patch COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgomp.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 From 52f7696b3442923f1c47f89c0cdd01ed27cf3be4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 25 Aug 2025 11:18:54 +0200 Subject: [PATCH 138/287] debug --- Images/qp-deblur/qp-deblur.dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 5b2a21b..90fc3ec 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -51,7 +51,8 @@ RUN pip install -U pip pip-system-certs RUN git clone -b uncouplePlugins https://github.com/jlab/qp-deblur.git RUN cd qp-deblur && pip install . -RUN echo "scikit-bio==0.5.5" > req.txt && echo "-e /qp-deblur" >> req.txt +RUN echo "scikit-bio==0.5.5" > req.txt && \ + echo "-e /qp-deblur" >> req.txt RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt @@ -127,7 +128,8 @@ RUN cd qiita_client && pip install . RUN mkdir -p /qiita_server_certificates/ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` --plugin-coupling filesystem +RUN cat /usr/local/bin/configure_deblur 1>&2 +RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` --plugin-coupling "filesystem" RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf # remove conda command from tigger.py From 334cba1eca2caa98ee486d51d1514d9b946be94a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 25 Aug 2025 11:29:10 +0200 Subject: [PATCH 139/287] more debug --- Images/qp-deblur/qp-deblur.dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 90fc3ec..6471783 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -129,6 +129,7 @@ RUN cd qiita_client && pip install . RUN mkdir -p /qiita_server_certificates/ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN cat /usr/local/bin/configure_deblur 1>&2 +RUN x=`find /qiita_server_certificates/ -name "*_server.crt" -type f`; echo "x: >$x<" 1>&2 RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` --plugin-coupling "filesystem" RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf From eef19bb1106fff0729b7ecacaafe309c6bf2e477 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 25 Aug 2025 11:53:31 +0200 Subject: [PATCH 140/287] create file to make find not fail --- .github/workflows/buildContainer.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index fc40833..343a2fe 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -29,6 +29,7 @@ jobs: cp Images/qp-deblur/start_qp-deblur.sh Images/qp-deblur/trigger_noconda.py . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem + echo "fake" > qiita_server_certificates/fake_server.crt - name: Build and push Docker image uses: docker/build-push-action@v6 with: From 14a9de5d3c1217558c8ea68cbefdb37e739ed016 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 25 Aug 2025 12:09:24 +0200 Subject: [PATCH 141/287] change dockerhub repo --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 343a2fe..ec5c94d 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -36,4 +36,4 @@ jobs: context: . push: true file: Images/qp-deblur/qp-deblur.dockerfile - tags: ${{ vars.DOCKERHUB_USERNAME }}/tinqiita-qp-deblur:${{ env.IMAGE_TAG }} \ No newline at end of file + tags: ${{ vars.DOCKERHUB_USERNAME }}/qp-deblur:${{ env.IMAGE_TAG }} \ No newline at end of file From 7bd715713b6d361a18bca83c7770c14d2a437081 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 25 Aug 2025 12:17:17 +0200 Subject: [PATCH 142/287] sync parameter name --- Images/qp-deblur/qp-deblur.dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 6471783..206cb77 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -128,9 +128,7 @@ RUN cd qiita_client && pip install . RUN mkdir -p /qiita_server_certificates/ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN cat /usr/local/bin/configure_deblur 1>&2 -RUN x=`find /qiita_server_certificates/ -name "*_server.crt" -type f`; echo "x: >$x<" 1>&2 -RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` --plugin-coupling "filesystem" +RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` plugincoupling "filesystem" RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf # remove conda command from tigger.py From 61c22f45477607b22a66589fcc2202a8fbc5cf9a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 25 Aug 2025 13:54:36 +0200 Subject: [PATCH 143/287] proper use of argzment --- Images/qp-deblur/qp-deblur.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 206cb77..a0d58ba 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -128,7 +128,7 @@ RUN cd qiita_client && pip install . RUN mkdir -p /qiita_server_certificates/ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` plugincoupling "filesystem" +RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` plugincoupling="filesystem" RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf # remove conda command from tigger.py From d27164e29ae6ddbdb9643df0e5f5a434adfb9bcf Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 25 Aug 2025 16:02:23 +0200 Subject: [PATCH 144/287] store dead end of qtp-biom smaller --- Images/qtp-biom/qtp-biom.dockerfile | 5 ++-- Images/qtp-biom/summary.py.patch | 46 +++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index e9406e3..a9b52df 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -59,7 +59,7 @@ RUN sed -i "s|'qiita-files @ https://github.com/qiita-spots/'||" setup.py RUN sed -i "s|'qiita-files/archive/master.zip',||" setup.py RUN sed -i "s|'qiita_client @ https://github.com/qiita-spots/'||" setup.py RUN sed -i "s|'qiita_client/archive/master.zip'||" setup.py -RUN sed -i "s|^import qiime2$|import qiime2.metadata|" qtp_biom/summary.py +# RUN sed -i "s|^import qiime2$|import qiime2.metadata|" qtp_biom/summary.py RUN pip install -e . RUN pip install --upgrade certifi @@ -69,7 +69,7 @@ RUN echo "-e /qiita_client" > req.txt RUN echo "-e /qiita-files" >> req.txt RUN echo "-e /qtp-biom" >> req.txt RUN echo "scikit-bio" >> req.txt -RUN echo "bp" >> req.txt +# RUN echo "bp==1.0.5" >> req.txt # RUN echo "flufl.lock" >> req.txt # RUN echo "decorator" >> req.txt # RUN echo "bibtexparser" >> req.txt @@ -135,6 +135,7 @@ COPY summary.py.patch /summary.py.patch WORKDIR / RUN patch -p0 < /summary.py.patch +COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/bp /usr/local/lib/python3.8/site-packages/bp COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgomp.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 # install tornado based trigger layer in base environment diff --git a/Images/qtp-biom/summary.py.patch b/Images/qtp-biom/summary.py.patch index b87c57b..60b2bae 100644 --- a/Images/qtp-biom/summary.py.patch +++ b/Images/qtp-biom/summary.py.patch @@ -1,33 +1,53 @@ ---- /usr/local/lib/python3.8/site-packages/qtp_biom/summary.py 2025-08-22 13:16:35.397740791 +0000 -+++ /exchange/summary.py 2025-08-22 18:22:40.548488772 +0000 +--- /usr/local/lib/python3.8/site-packages/qtp_biom/summary.py 2025-08-22 22:16:54.361692587 +0000 ++++ /exchange/summary.py.new 2025-08-22 22:16:20.964222594 +0000 @@ -12,8 +12,11 @@ import pandas as pd from tempfile import mkstemp --import qiime2.metadata +-import qiime2 -from qiime2.plugins.feature_table.visualizers import summarize -+# import qiime2.metadata ++# import qiime2 +# from qiime2.plugins.feature_table.visualizers import summarize +import sys +sys.path.append("/") -+from q2summarize import * # this is a stripped, patched version from the above but comes with way less q2 dependencies! ++from q2summarize import summarize as q2_summarize # this is a stripped, patched version from the above but comes with way less q2 dependencies! from skbio.tree import TreeNode from biom import load_table -@@ -57,12 +60,12 @@ +@@ -57,19 +60,19 @@ df = pd.DataFrame.from_dict(metadata, orient='index') df.to_csv(path, index_label='#SampleID', na_rep='', sep='\t', encoding='utf-8') - metadata = qiime2.Metadata.load(path) -+ metadata = df # orig: qiime2.Metadata.load(path) ++ metadata = df # qiime2.Metadata.load(path) remove(path) -- else: + else: - metadata = qiime2.Metadata.load(metadata) -+ # else: -+ # metadata = qiime2.Metadata.load(metadata) ++ metadata = pd.read_csv(metadata, sep="\t", index_col=0) # qiime2.Metadata.load(metadata) - table = qiime2.Artifact.import_data('FeatureTable[Frequency]', biom_fp) -+ table = load_table(biom_fp) # orig: qiime2.Artifact.import_data('FeatureTable[Frequency]', biom_fp) ++ table = load_table(biom_fp) # qiime2.Artifact.import_data('FeatureTable[Frequency]', biom_fp) - summary, = summarize(table=table, sample_metadata=metadata) - index_paths = summary.get_index_paths() +- summary, = summarize(table=table, sample_metadata=metadata) +- index_paths = summary.get_index_paths() ++ q2_summarize(out_dir, table=table, sample_metadata=metadata) ++ # index_paths = summary.get_index_paths() + # this block is not really necessary but better safe than sorry +- if 'html' not in index_paths: +- return (False, None, +- "Only Qiime 2 visualization with an html index are supported") ++ # if 'html' not in index_paths: ++ # return (False, None, ++ # "Only Qiime 2 visualization with an html index are supported") + + # gather some stats about the phylogenetic tree if exists + summary_tree = "" +@@ -99,7 +102,7 @@ + " ") % (num_placements, num_rejected, + num_tips_reference) + +- index_name = basename(index_paths['html']) ++ index_name = 'index.html' # basename(index_paths['html']) + index_fp = join(out_dir, 'index.html') + with open(index_fp, 'w') as f: + f.write(Q2_INDEX % (summary_tree, index_name)) From 274e8b2ca6cb73313f3dcb4848945953b25b6a58 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 10:18:34 +0200 Subject: [PATCH 145/287] a working (but still large) version for qtp-biom with q2-tiny --- Images/qtp-biom/qtp-biom.dockerfile | 222 +++------------------------- Images/qtp-biom/start_qtp-biom.sh | 2 +- Makefile | 4 +- 3 files changed, 26 insertions(+), 202 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index a9b52df..2865d84 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -1,9 +1,4 @@ -# VERSION: 2025.08.22 - -# ========================== -# Stage 1: Build wheels -# ========================== -FROM ubuntu:24.04 AS builder +FROM ubuntu:24.04 ARG MINIFORGE_VERSION=24.1.2-0 @@ -32,123 +27,43 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh -# Download qtp-biom yaml -RUN wget https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml +# install tornado based trigger layer in base environment +RUN pip install -U pip +RUN conda install tornado +COPY trigger.py /trigger.py +# Download qtp-biom yaml +RUN wget https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/2025.7/tiny/released/qiime2-tiny-ubuntu-latest-conda.yml +RUN echo "- q2-feature-table" >> qiime2-tiny-ubuntu-latest-conda.yml +RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/2025.7/amplicon/released/\n- conda-forge|" qiime2-tiny-ubuntu-latest-conda.yml # Create conda env -RUN conda env create --quiet -n qtp-biom --file qiime2-2022.11-py38-linux-conda.yml +RUN conda env create --quiet -n qtp-biom --file qiime2-tiny-ubuntu-latest-conda.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] -WORKDIR / -RUN git clone https://github.com/qiita-spots/qiita_client.git -WORKDIR qiita_client -RUN pip install . - -WORKDIR / -RUN git clone https://github.com/qiita-spots/qiita-files.git -WORKDIR qiita-files -RUN pip install . - -WORKDIR / -RUN git clone https://github.com/qiita-spots/qtp-biom.git -WORKDIR /qtp-biom -RUN sed -i "s|, 'qiime2', |, |" setup.py -RUN sed -i "s|'qiita-files @ https://github.com/qiita-spots/'||" setup.py -RUN sed -i "s|'qiita-files/archive/master.zip',||" setup.py -RUN sed -i "s|'qiita_client @ https://github.com/qiita-spots/'||" setup.py -RUN sed -i "s|'qiita_client/archive/master.zip'||" setup.py -# RUN sed -i "s|^import qiime2$|import qiime2.metadata|" qtp_biom/summary.py - +RUN pip install -U pip +RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +# RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +COPY ./qiita-files /qiita-files +RUN cd /qiita-files && pip install -e . -v +# RUN git clone https://github.com/qiita-spots/qtp-biom.git +COPY ./qtp-biom /qtp-biom +WORKDIR qtp-biom RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs +RUN conda install tornado +COPY trigger.py /trigger.py -RUN echo "-e /qiita_client" > req.txt -RUN echo "-e /qiita-files" >> req.txt -RUN echo "-e /qtp-biom" >> req.txt -RUN echo "scikit-bio" >> req.txt -# RUN echo "bp==1.0.5" >> req.txt -# RUN echo "flufl.lock" >> req.txt -# RUN echo "decorator" >> req.txt -# RUN echo "bibtexparser" >> req.txt -# RUN echo "tzlocal" >> req.txt -# RUN echo "dill" >> req.txt -# RUN echo "charset_normalizer==2.1.1" >> req.txt -RUN echo "biom-format" >> req.txt -RUN echo "seaborn" >> req.txt -RUN echo "jinja2" >> req.txt -RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt - -RUN mkdir -p /unshared_plugins -ENV QIITA_PLUGINS_DIR=/unshared_plugins/ - -## Export cert and config filepaths -COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem -# ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem -# ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem - -#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` -RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf -#RUN sed -i "s|self._verify = ca_cert|self._verify = False|" /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiita_client/qiita_client.py - -ARG Q2_RELEASE=2022.11 -WORKDIR /q2_src/ -RUN wget "https://github.com/qiime2/q2-feature-table/archive/refs/tags/${Q2_RELEASE}.0.tar.gz" -O - | tar -xzvf - -RUN wget "https://github.com/qiime2/q2templates/archive/refs/tags/${Q2_RELEASE}.0.tar.gz" -O - | tar -xzvf - - -# ========================== -# Stage 2: Runtime -# ========================== -FROM python:3.8-slim - -# python package compile in build stage -COPY --from=builder /wheels /wheels -# ^^ ?? MB - - -RUN pip install --no-cache-dir /wheels/* -ARG Q2_RELEASE=2022.11 - -COPY --from=builder /q2_src/q2-feature-table-${Q2_RELEASE}.0/q2_feature_table/_summarize /q2summarize/ -COPY --from=builder /q2_src/q2templates-${Q2_RELEASE}.0/q2templates/util.py /q2summarize/util.py -COPY --from=builder /q2_src/q2templates-${Q2_RELEASE}.0/q2templates/_templates.py /q2summarize/_templates.py -COPY --from=builder /q2_src/q2templates-${Q2_RELEASE}.0/q2templates/templates /q2summarize/templates/ -RUN sed -i "s|from .util import|import sys; sys.path.append('/'); from q2summarize.util import|" /q2summarize/_templates.py -RUN sed -i "s|pkg_resources.resource_filename('q2templates', 'templates')|'/q2summarize/templates/'|" /q2summarize/_templates.py -RUN sed -i "s|pd.option_context('display.max_colwidth', -1)|pd.option_context('display.max_colwidth', None)|" /q2summarize/util.py -RUN sed -i "s|sample_metadata = sample_metadata.filter_ids(|df = sample_metadata.loc[[s for s in sample_frequencies.index if s in sample_metadata.index], :]|" /q2summarize/_vega_spec.py -RUN sed -i "s|^[[:space:]]*sample_frequencies.index)||" /q2summarize/_vega_spec.py -RUN sed -i "s|df = sample_metadata.to_dataframe()||" /q2summarize/_vega_spec.py -RUN echo "from ._visualizer import summarize; __all__ = ['summarize']" > /q2summarize/__init__.py - -RUN apt-get -y update -RUN apt-get -y --fix-missing install patch -WORKDIR /q2summarize -COPY _visualizer.py.patch /q2summarize/ -RUN patch -p1 _visualizer.py < _visualizer.py.patch -# # COPY --from=builder /q2_src/ /q2_all -COPY summary.py.patch /summary.py.patch -WORKDIR / -RUN patch -p0 < /summary.py.patch - -COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/bp /usr/local/lib/python3.8/site-packages/bp -COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgomp.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 - -# install tornado based trigger layer in base environment -RUN pip install -U --no-cache-dir tornado pip-system-certs -COPY trigger_noconda.py /trigger.py -# ^^ 848 MB +# TODO: should the plugin get the server configuration?! +RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg WORKDIR / COPY start_qtp-biom.sh . RUN chmod 755 start_qtp-biom.sh - RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ @@ -157,100 +72,9 @@ COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certi ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem -RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/configure_biom -RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/start_biom - #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /usr/local/bin/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf -# remove conda command from tigger.py -RUN sed -i "s|source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s;||" /trigger.py && sed -i "s|conda_env_name, ||" /trigger.py - CMD ["./start_qtp-biom.sh"] - -#/usr/local/lib/python3.8/site-packages/qtp_biom/summary.py - -# COPY 2_20250704-123139.txt /q2summarize/2_20250704-123139.txt -# COPY reference-hit.biom /q2summarize/ -# RUN mkdir -p /q2summarize/test.xxx -#/usr/local/lib/python3.8/site-packages - -#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2 /usr/local/lib/python3.8/site-packages/qiime2 -#COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/qiime2-2022.11.1-py3.8.egg-info /usr/local/lib/python3.8/site-packages/ -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/ -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libopenblasp-r0.3.21.so /usr/local/lib/libopenblasp-r0.3.21.so -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libgfortran.so.5.0.0 /usr/local/lib/libgfortran.so.5 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libquadmath.so.0.0.0 /usr/local/lib/libquadmath.so.0 - -# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libcblas.so.3 -# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/libblas.so.3 -# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapack.so.3 -# RUN ln -s /usr/local/lib/libopenblasp-r0.3.21.so /usr/local/lib/liblapacke.so.3 - -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libcrypto.so.1.1 /usr/local/lib/libcrypto.so.1.1 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libcurl.so.4.8.0 /usr/local/lib/libcurl.so.4 - -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libnghttp2.so.14.24.1 /usr/local/lib/libnghttp2.so.14 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libssh2.so.1.0.1 /usr/local/lib/libssh2.so.1 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libssh2.so.1.0.1 /usr/local/lib/libssh2.so.1 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libssl.so.1.1 /usr/local/lib/libssl.so.1.1 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libjpeg.so.9.5.0 /usr/local/lib/libjpeg.so.9 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libopenjp2.so.2.5.0 /usr/local/lib/libopenjp2.so.7 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libtiff.so.5.8.0 /usr/local/lib/libtiff.so.5 - -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libLerc.so.4 /usr/local/lib/libLerc.so.4 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libdeflate.so.0 /usr/local/lib/libdeflate.so.0 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libfreetype.so.6.18.3 /usr/local/lib/libfreetype.so.6 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/liblcms2.so.2.0.14 /usr/local/lib/iblcms2.so.2 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libwebp.so.7.1.5 /usr/local/lib/libwebp.so.7 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libwebpdemux.so.2.0.11 /usr/local/lib/libwebpdemux.so.2 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libwebpmux.so.3.0.10 /usr/local/lib/libwebpmux.so.3 -# COPY --from=builder /opt/conda/envs/qtp-biom/lib/libxcb.so.1.1.0 /usr/local/lib/libxcb.so.1 - -# ENV REQUESTS_CA_BUNDLE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem -# ENV SSL_CERT_FILE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem -# RUN pip install biom-format - -#libwebp.so.7 libwebpmux.so.3 libwebpdemux.so.2 liblcms2.so.2 libfreetype.so.6 libxcb.so.1 libwebp.so.7 libLerc.so.4 libdeflate.so.0 - -# WORKDIR /usr/local/lib/python3.8/site-packages/qtp_biom -# RUN echo 'python summary.py' > /root/.bash_history -# # # RUN pip install -U pip -# # RUN conda install tornado -# # COPY trigger.py /trigger.py - - -# # COPY start_qtp-biom.sh . -# # RUN chmod 755 start_qtp-biom.sh - -# # RUN mkdir -p /unshared_plugins -# # ENV QIITA_PLUGINS_DIR=/unshared_plugins/ - -# # ## Export cert and config filepaths -# # COPY Certificates /unshared_certificates -# # RUN cat /unshared_certificates/stefan_rootca.crt >> `python -c "import certifi; print(certifi.where())"` # append own rootCA onto chain of trust -# # RUN export REQUESTS_CA_BUNDLE=`python -c "import certifi; print(certifi.where())"` -# # RUN export SSL_CERT_FILE=`python -c "import certifi; print(certifi.where())"` - -# # #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -# # RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert /unshared_certificates/stefan_server.crt -# # RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf - -# # CMD ["./start_qtp-biom.sh"] - - - - - - - - -# export REQUESTS_CA_BUNDLE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem -# export SSL_CERT_FILE=/opt/conda/lib/python3.10/site-packages/certifi/cacert.pem -# pip install biom-format seaborn jinja2 -# cd /_summarize && mkdir -p /test.xxx -# python _visualizer.py \ No newline at end of file diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index dc62c7e..3ab12c4 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py start_biom +cd / && python trigger.py qtp-biom start_biom /qtp-biom tail -f /dev/null diff --git a/Makefile b/Makefile index 0dd25ab..58b64ea 100644 --- a/Makefile +++ b/Makefile @@ -34,10 +34,10 @@ $(DIR_REFERENCES)/qiita_server_certificates: Images/plugin_collector/stefan_csr. plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REFERENCES)/qiita_server_certificates cp -r $^ $(tmpdir)/ -.built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh Images/qtp-biom/_visualizer.py.patch Images/qtp-biom/summary.py.patch +.built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh src/qiita-files/ src/qtp-biom/ test -d src/qtp-biom || git clone https://github.com/qiita-spots/qtp-biom.git src/qtp-biom tmpdir=$(TMPDIR) $(MAKE) plugin - cp $^ $(TMPDIR) + cp -r $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` From cc952553d975db1deb86fc688a53392ed4337b3e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:35:58 +0200 Subject: [PATCH 146/287] defining a pip dependency list via external file --- Images/qtp-biom/requirements.txt | 29 +++++++++++++++++++++++++++++ Makefile | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Images/qtp-biom/requirements.txt diff --git a/Images/qtp-biom/requirements.txt b/Images/qtp-biom/requirements.txt new file mode 100644 index 0000000..a32d2ee --- /dev/null +++ b/Images/qtp-biom/requirements.txt @@ -0,0 +1,29 @@ +-e /q2-feature-table +-e /q2-metadata +-e /q2-mystery-stew +-e /q2-types +-e /q2cli +-e /q2templates +-e /qiime2 + +pyyaml +decorator +tzlocal +bibtexparser +psutil +flufl.lock +parsl +appdirs +tomlkit +scikit-bio +rnanorm +seaborn +jinja2 +ijson +pyhmmer +frictionless +numpy==1.26.4 + +-e /qtp-biom +-e /qiita-files +-e /qiita_client diff --git a/Makefile b/Makefile index 58b64ea..1878601 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ $(DIR_REFERENCES)/qiita_server_certificates: Images/plugin_collector/stefan_csr. plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REFERENCES)/qiita_server_certificates cp -r $^ $(tmpdir)/ -.built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh src/qiita-files/ src/qtp-biom/ +.built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh src/qiita-files/ src/qtp-biom/ Images/qtp-biom/requirements.txt test -d src/qtp-biom || git clone https://github.com/qiita-spots/qtp-biom.git src/qtp-biom tmpdir=$(TMPDIR) $(MAKE) plugin cp -r $^ $(TMPDIR) From 1c3e85910f9293cdf48485d485a68f3d6c6cd4ec Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:36:23 +0200 Subject: [PATCH 147/287] no conda anymore --- Images/qtp-biom/start_qtp-biom.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-biom/start_qtp-biom.sh b/Images/qtp-biom/start_qtp-biom.sh index 3ab12c4..dc62c7e 100644 --- a/Images/qtp-biom/start_qtp-biom.sh +++ b/Images/qtp-biom/start_qtp-biom.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py qtp-biom start_biom /qtp-biom +cd / && python trigger.py start_biom tail -f /dev/null From 2c57bf96e0c6aa46061c00a664ea2bf44d5dbebd Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:36:49 +0200 Subject: [PATCH 148/287] working and small version for qtp-biom, dockfile needs some more cleanup! --- Images/qtp-biom/qtp-biom.dockerfile | 79 +++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 2865d84..1d92352 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -1,6 +1,7 @@ -FROM ubuntu:24.04 +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 +ARG QIITARELEASE=2025.7 ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} @@ -33,9 +34,9 @@ RUN conda install tornado COPY trigger.py /trigger.py # Download qtp-biom yaml -RUN wget https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/2025.7/tiny/released/qiime2-tiny-ubuntu-latest-conda.yml +RUN wget https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/${QIITARELEASE}/tiny/released/qiime2-tiny-ubuntu-latest-conda.yml RUN echo "- q2-feature-table" >> qiime2-tiny-ubuntu-latest-conda.yml -RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/2025.7/amplicon/released/\n- conda-forge|" qiime2-tiny-ubuntu-latest-conda.yml +RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/${QIITARELEASE}/amplicon/released/\n- conda-forge|" qiime2-tiny-ubuntu-latest-conda.yml # Create conda env RUN conda env create --quiet -n qtp-biom --file qiime2-tiny-ubuntu-latest-conda.yml # Make RUN commands use the new environment: @@ -43,7 +44,11 @@ RUN conda env create --quiet -n qtp-biom --file qiime2-tiny-ubuntu-latest-conda. SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] RUN pip install -U pip -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +# RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py +RUN cd qiita_client && pip install --no-cache-dir . + # RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip COPY ./qiita-files /qiita-files RUN cd /qiita-files && pip install -e . -v @@ -77,4 +82,70 @@ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf +# prepare for runtime stage +WORKDIR / +RUN pip uninstall pip-system-certs -y +RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-feature-table.git +RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-metadata.git +RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-mystery-stew.git +RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-types.git +RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2cli.git +RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2templates.git +RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/qiime2.git + +COPY requirements.txt ./requirements.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt + +CMD ["./start_qtp-biom.sh"] + +# ========================== +# Stage 2: Runtime +# ========================== +FROM python:3.10-slim + +# python package compile in build stage +COPY --from=builder /wheels /wheels + +RUN pip install --no-cache-dir /wheels/* \ + && rm -rf rm -rf `find /usr/local/lib/python3.10/site-packages -type d -name "tests" | grep -v numpy` +# ^^ 788MB + +COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.10/site-packages/bp /usr/local/lib/python3.10/site-packages/bp + +# install tornado based trigger layer in base environment +RUN pip install -U --no-cache-dir tornado +COPY trigger_noconda.py /trigger.py + +WORKDIR / + +COPY start_qtp-biom.sh . +RUN chmod 755 start_qtp-biom.sh + +RUN mkdir -p /unshared_plugins +ENV QIITA_PLUGINS_DIR=/unshared_plugins/ + +RUN pip install pip-system-certs + +RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/configure_biom +RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/start_biom + +# use git branch instead of pypi version (stored via wheel) +#COPY --from=builder /qiita_client /qiita_client +#RUN cd qiita_client && pip install . + +## Export cert and config filepaths +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem + +RUN mkdir -p /qiita_server_certificates/ +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN /usr/local/bin/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf + +# remove conda command from tigger.py +# RUN sed -i "s|source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s;||" /trigger.py && sed -i "s|conda_env_name, ||" /trigger.py + CMD ["./start_qtp-biom.sh"] + +# python -c "import qiime2.plugins.feature_table" \ No newline at end of file From f5bc5fe9210ddb29358eceb4ad1c5211d44f4fd6 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:42:58 +0200 Subject: [PATCH 149/287] adding version --- Images/qtp-biom/qtp-biom.dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 1d92352..14502de 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.08.26 + FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 From 0ee1f23a289016b8cb9be17cb0598d1421e181d8 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:43:10 +0200 Subject: [PATCH 150/287] also build biom --- .github/workflows/buildContainer.yaml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index ec5c94d..3dfb04d 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -7,6 +7,9 @@ on: jobs: docker: + strategy: + matrix: + plugin: ["qp-deblur", "qtp-biom"] runs-on: ubuntu-latest steps: - name: Checkout repository @@ -24,9 +27,9 @@ jobs: - name: Read version from file id: vars run: | - VERSION=$(head -n 1 Images/qp-deblur/qp-deblur.dockerfile | cut -d ":" -f 2- | tr -d " ") + VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/qp-deblur/start_qp-deblur.sh Images/qp-deblur/trigger_noconda.py . + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/requirements.txt . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt @@ -35,5 +38,5 @@ jobs: with: context: . push: true - file: Images/qp-deblur/qp-deblur.dockerfile - tags: ${{ vars.DOCKERHUB_USERNAME }}/qp-deblur:${{ env.IMAGE_TAG }} \ No newline at end of file + file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + tags: ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} From 41a08e1e86266d2078c6df0a1aca3ce7667fceb9 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:45:41 +0200 Subject: [PATCH 151/287] adding trigger.py file --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 3dfb04d..2df3c2d 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -29,7 +29,7 @@ jobs: run: | VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/requirements.txt . + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/qtp-biom/requirements.txt . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt From b7630d8ad904fa88873bc3401a435faae5a025c7 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:48:54 +0200 Subject: [PATCH 152/287] source from git instead local copy --- Images/qtp-biom/qtp-biom.dockerfile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 14502de..b23dd9b 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -54,9 +54,13 @@ RUN cd qiita_client && pip install --no-cache-dir . # RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip COPY ./qiita-files /qiita-files RUN cd /qiita-files && pip install -e . -v -# RUN git clone https://github.com/qiita-spots/qtp-biom.git -COPY ./qtp-biom /qtp-biom +RUN git clone https://github.com/qiita-spots/qtp-biom.git +# COPY ./qtp-biom /qtp-biom WORKDIR qtp-biom +RUN sed -i "s|'qiita-files @ https://github.com/qiita-spots/'||" setup.py +RUN sed -i "s|'qiita-files/archive/master.zip',||" setup.py +RUN sed -i "s|'qiita_client @ https://github.com/qiita-spots/'||" setup.py +RUN sed -i "s|'qiita_client/archive/master.zip'||" setup.py RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs From 33ace7e468dbe74ef24a9d87572386b3e438712b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 12:52:31 +0200 Subject: [PATCH 153/287] qiita-files from repo --- Images/qtp-biom/qtp-biom.dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index b23dd9b..2b25b3a 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -52,11 +52,12 @@ RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Ente RUN cd qiita_client && pip install --no-cache-dir . # RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip -COPY ./qiita-files /qiita-files +RUN git clone -b migrate_py310 https://github.com/jlab/qiita-files.git +# COPY ./qiita-files /qiita-files RUN cd /qiita-files && pip install -e . -v RUN git clone https://github.com/qiita-spots/qtp-biom.git # COPY ./qtp-biom /qtp-biom -WORKDIR qtp-biom +WORKDIR /qtp-biom RUN sed -i "s|'qiita-files @ https://github.com/qiita-spots/'||" setup.py RUN sed -i "s|'qiita-files/archive/master.zip',||" setup.py RUN sed -i "s|'qiita_client @ https://github.com/qiita-spots/'||" setup.py From 1e4430d7fb85d5acca2136df9a8677c816063fca Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 26 Aug 2025 13:01:37 +0200 Subject: [PATCH 154/287] cleanup and moving crt issue to stage 2 --- Images/qtp-biom/qtp-biom.dockerfile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 2b25b3a..0bb9df4 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -73,24 +73,24 @@ RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg WORKDIR / -COPY start_qtp-biom.sh . -RUN chmod 755 start_qtp-biom.sh +#COPY start_qtp-biom.sh . +#RUN chmod 755 start_qtp-biom.sh -RUN mkdir -p /unshared_plugins -ENV QIITA_PLUGINS_DIR=/unshared_plugins/ +#RUN mkdir -p /unshared_plugins +#ENV QIITA_PLUGINS_DIR=/unshared_plugins/ ## Export cert and config filepaths -COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem -ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem -ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem +#COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +#ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +#ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` -RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf +#COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +#RUN /qtp-biom/scripts/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +#RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf # prepare for runtime stage -WORKDIR / +# WORKDIR / RUN pip uninstall pip-system-certs -y RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-feature-table.git RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-metadata.git From 16dd895b9b1dfc9280124ac2b4f25c8a4dcee70b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 27 Aug 2025 14:46:32 +0200 Subject: [PATCH 155/287] arg plugincoupling without arg name --- Images/qp-deblur/qp-deblur.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index a0d58ba..1e42272 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -128,7 +128,7 @@ RUN cd qiita_client && pip install . RUN mkdir -p /qiita_server_certificates/ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` plugincoupling="filesystem" +RUN /usr/local/bin/configure_deblur --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` filesystem RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-deblur/" /unshared_plugins/*.conf # remove conda command from tigger.py From 506141f814e491dfebce7f31aa1db7de885c1ee4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 09:17:44 +0200 Subject: [PATCH 156/287] adding shrunk container for qp-target-gene --- .github/workflows/buildContainer.yaml | 2 +- .../qp-target-gene/qp-target-gene.dockerfile | 68 +++++++++++++++---- Images/qp-target-gene/requirements.txt | 5 ++ Images/qp-target-gene/start_qp-target-gene.sh | 2 +- Makefile | 2 +- 5 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 Images/qp-target-gene/requirements.txt diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 2df3c2d..f7f7a4a 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom"] + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene"] runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index ddb2309..588190b 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -1,4 +1,9 @@ -FROM ubuntu:24.04 +# VERSION: 2025.08.28 + +# ========================== +# Stage 1: Build wheels +# ========================== +FROM ubuntu:24.04 as builder ARG MINIFORGE_VERSION=24.1.2-0 @@ -25,8 +30,6 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ # install tornado based trigger layer in base environment RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py # Create conda env RUN conda create --name qp-target-gene -y -c conda-forge -c bioconda -c biocore python=2.7 SortMeRNA==2.0 numpy==1.13.1 pigz biom-format @@ -35,39 +38,80 @@ RUN conda create --name qp-target-gene -y -c conda-forge -c bioconda -c biocore SHELL ["conda", "run", "-p", "/opt/conda/envs/qp-target-gene", "/bin/bash", "-c"] # see https://stackoverflow.com/questions/49940813/pip-no-module-named-internal -RUN wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O get-pip.py -RUN python2.7 get-pip.py --force-reinstall +RUN wget https://bootstrap.pypa.io/pip/2.7/get-pip.py -O /get-pip2.7.py +RUN wget https://bootstrap.pypa.io/pip/3.7/get-pip.py -O /get-pip3.7.py +RUN python2.7 get-pip2.7.py --force-reinstall RUN pip install -U pip -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +#RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN cd qiita_client && pip install --no-cache-dir . + RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip RUN git clone https://github.com/qiita-spots/qp-target-gene.git -WORKDIR qp-target-gene +WORKDIR /qp-target-gene RUN pip install biom-format RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg - WORKDIR / +COPY requirements.txt ./requirements.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt + + +# ========================== +# Stage 2: Runtime +# ========================== +# I am testing ubuntu as base image, since python:xxx-slim was too hard/large to install python2 and python3 side by side +FROM ubuntu:22.04 + +# py2 and py3 +RUN mkdir -p /usr/share/man/man1 && \ + apt-get update && \ + apt-get install -y --no-install-recommends python2 python3 curl && \ + rm -rf /var/lib/apt/lists/* + +# # RUN apk add --no-cache python2 python3 curl + +# pip2 installieren +COPY --from=builder /get-pip2.7.py /get-pip3.7.py / +RUN python2 get-pip2.7.py \ + && rm get-pip2.7.py + +# pip3 installieren +RUN python3 get-pip3.7.py \ + && rm get-pip3.7.py + +# python package compile in build stage +COPY --from=builder /wheels /wheels + +# dependent binaries + necessary libraries: sortmerna +COPY --from=builder /opt/conda/envs/qp-target-gene/bin/indexdb_rna /opt/conda/envs/qp-target-gene/bin/sortmerna /usr/local/bin/ + +RUN pip2 install --no-cache-dir /wheels/* \ + && rm -rf rm -rf `find /usr/local/lib/python2.7/site-packages -type d -name "tests" | grep -v numpy` + COPY start_qp-target-gene.sh . RUN chmod 755 start_qp-target-gene.sh RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ +RUN pip3 install tornado +COPY trigger_noconda.py /trigger.py + ## Export cert and config filepaths COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" $CONDA_PREFIX/lib/python2.7/site-packages/qiita_client/plugin.py COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /qp-target-gene/scripts/configure_target_gene --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN sed -i "s|^#\!.*|#\!/usr/bin/python2|" /usr/local/bin/configure_target_gene +RUN sed -i "s|^#\!.*|#\!/usr/bin/python2|" /usr/local/bin/start_target_gene +RUN configure_target_gene --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-target-gene/" /unshared_plugins/*.conf CMD ["./start_qp-target-gene.sh"] diff --git a/Images/qp-target-gene/requirements.txt b/Images/qp-target-gene/requirements.txt new file mode 100644 index 0000000..8c07d47 --- /dev/null +++ b/Images/qp-target-gene/requirements.txt @@ -0,0 +1,5 @@ +pip-system-certs + +https://github.com/qiita-spots/qiita-files/archive/master.zip +-e /qiita_client +-e /qp-target-gene diff --git a/Images/qp-target-gene/start_qp-target-gene.sh b/Images/qp-target-gene/start_qp-target-gene.sh index 9749354..cf92cee 100644 --- a/Images/qp-target-gene/start_qp-target-gene.sh +++ b/Images/qp-target-gene/start_qp-target-gene.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py qp-target-gene start_target_gene /qp-target-gene +cd / && python3 trigger.py start_target_gene tail -f /dev/null diff --git a/Makefile b/Makefile index 1878601..b83687a 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qp-target-gene: Images/qp-target-gene/qp-target-gene.dockerfile Images/qp-target-gene/start_qp-target-gene.sh +.built_image_qp-target-gene: Images/qp-target-gene/qp-target-gene.dockerfile Images/qp-target-gene/start_qp-target-gene.sh Images/qp-target-gene/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From eb4285ca77908387645c3bab8380b9209d613d97 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 09:41:24 +0200 Subject: [PATCH 157/287] install additional dependency + copy library --- Images/qp-target-gene/qp-target-gene.dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index 588190b..2448f5c 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -70,7 +70,7 @@ FROM ubuntu:22.04 # py2 and py3 RUN mkdir -p /usr/share/man/man1 && \ apt-get update && \ - apt-get install -y --no-install-recommends python2 python3 curl && \ + apt-get install -y --no-install-recommends python2 python3 curl python-tk && \ rm -rf /var/lib/apt/lists/* # # RUN apk add --no-cache python2 python3 curl @@ -92,6 +92,7 @@ COPY --from=builder /opt/conda/envs/qp-target-gene/bin/indexdb_rna /opt/conda/en RUN pip2 install --no-cache-dir /wheels/* \ && rm -rf rm -rf `find /usr/local/lib/python2.7/site-packages -type d -name "tests" | grep -v numpy` +COPY --from=builder /opt/conda/envs/qp-target-gene/lib/libpython2.7.so.1.0 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 COPY start_qp-target-gene.sh . RUN chmod 755 start_qp-target-gene.sh From 3133cdab30864a9ec9019bb1d8da333e32e8a9a7 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 09:52:10 +0200 Subject: [PATCH 158/287] also make deblur use a requirements.txt file for pip install in stage 2 --- .github/workflows/buildContainer.yaml | 2 +- Images/qp-deblur/qp-deblur.dockerfile | 5 ++--- Images/qp-deblur/requirements.txt | 3 +++ Makefile | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 Images/qp-deblur/requirements.txt diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index f7f7a4a..54db067 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -29,7 +29,7 @@ jobs: run: | VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/qtp-biom/requirements.txt . + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/${{ matrix.plugin }}/requirements.txt . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 1e42272..5029339 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -51,9 +51,8 @@ RUN pip install -U pip pip-system-certs RUN git clone -b uncouplePlugins https://github.com/jlab/qp-deblur.git RUN cd qp-deblur && pip install . -RUN echo "scikit-bio==0.5.5" > req.txt && \ - echo "-e /qp-deblur" >> req.txt -RUN pip wheel --no-cache-dir --wheel-dir /wheels -r req.txt +COPY requirements.txt ./requirements.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt # ========================== diff --git a/Images/qp-deblur/requirements.txt b/Images/qp-deblur/requirements.txt new file mode 100644 index 0000000..37e968b --- /dev/null +++ b/Images/qp-deblur/requirements.txt @@ -0,0 +1,3 @@ +scikit-bio==0.5.5 + +-e /qp-deblur \ No newline at end of file diff --git a/Makefile b/Makefile index b83687a..9c87dee 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ $(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre: cp $(DIR_REFERENCES)/tmp_sepp/share/fragment-insertion/ref/* $(DIR_REFERENCES)/qp-deblur/ rm -rf $(DIR_REFERENCES)/tmp_sepp/ -.built_image_qp-deblur: Images/qp-deblur/qp-deblur.dockerfile Images/qp-deblur/start_qp-deblur.sh $(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre +.built_image_qp-deblur: Images/qp-deblur/qp-deblur.dockerfile Images/qp-deblur/start_qp-deblur.sh $(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre Images/qp-deblur/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From 76dd901c14a833df49716e321e121cfbd4e3f3ac Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 11:20:45 +0200 Subject: [PATCH 159/287] first attempt to shrink qtp-sequences --- .../qtp-sequencing/qtp-sequencing.dockerfile | 56 +++++++++++++------ Images/qtp-sequencing/requirements.txt | 6 ++ Images/qtp-sequencing/start_qtp-sequencing.sh | 2 +- Makefile | 2 +- 4 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 Images/qtp-sequencing/requirements.txt diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index a7f6750..d5712e5 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -1,4 +1,9 @@ -FROM ubuntu:24.04 +# VERSION: 2025.08.28 + +# ========================== +# Stage 1: Build wheels (~5.8 GB) +# ========================== +FROM ubuntu:24.04 as builder ARG MINIFORGE_VERSION=24.1.2-0 @@ -23,11 +28,6 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh -# install tornado based trigger layer in base environment -RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py - # Create conda env RUN conda create --name qtp-sequencing -y -c conda-forge -c bioconda pip pigz quast fqtools python=3.9 # Make RUN commands use the new environment: @@ -35,18 +35,44 @@ RUN conda create --name qtp-sequencing -y -c conda-forge -c bioconda pip pigz qu SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-sequencing", "/bin/bash", "-c"] RUN pip install -U pip -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +#RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN cd qiita_client && pip install --no-cache-dir . + +# RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone -b master https://github.com/qiita-spots/qiita-files.git +RUN cd /qiita-files && pip install -e . -v + RUN git clone https://github.com/qiita-spots/qtp-sequencing.git -WORKDIR qtp-sequencing +WORKDIR /qtp-sequencing +RUN sed -i "s|'qiita-files @ https://github.com/'||" setup.py +RUN sed -i "s|'qiita-spots/qiita-files/archive/master.zip',||" setup.py +RUN sed -i "s|'qiita_client @ https://github.com/'||" setup.py +RUN sed -i "s|'qiita-spots/qiita_client/archive/master.zip'||" setup.py RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg +COPY requirements.txt ./requirements.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt + +# ========================== +# Stage 2: Runtime +# ========================== +FROM python:3.9-slim + +# python package compile in build stage +COPY --from=builder /wheels /wheels + +RUN pip install --no-cache-dir /wheels/* \ + && rm -rf rm -rf `find /usr/local/lib/python3.9/site-packages -type d -name "tests" | grep -v numpy` + +# # install tornado based trigger layer in base environment +# RUN pip install -U pip +# RUN pip install tornado +COPY trigger_noconda.py /trigger.py -WORKDIR / +# WORKDIR / COPY start_qtp-sequencing.sh . RUN chmod 755 start_qtp-sequencing.sh @@ -59,10 +85,8 @@ COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certi ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem -#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /qtp-sequencing/scripts/configure_qtp_sequencing --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN configure_qtp_sequencing --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-sequencing/" /unshared_plugins/*.conf -#CMD ["conda", "run", "-n", "qtp-sequencing", "./start_qtp-sequencing.sh"] -CMD ["./start_qtp-sequencing.sh"] +CMD ["./start_qtp-sequencing.sh"] \ No newline at end of file diff --git a/Images/qtp-sequencing/requirements.txt b/Images/qtp-sequencing/requirements.txt new file mode 100644 index 0000000..1c88c0e --- /dev/null +++ b/Images/qtp-sequencing/requirements.txt @@ -0,0 +1,6 @@ +tornado +pip-system-certs + +-e /qiita_client +-e /qiita-files +-e /qtp-sequencing \ No newline at end of file diff --git a/Images/qtp-sequencing/start_qtp-sequencing.sh b/Images/qtp-sequencing/start_qtp-sequencing.sh index a740816..d9ab477 100644 --- a/Images/qtp-sequencing/start_qtp-sequencing.sh +++ b/Images/qtp-sequencing/start_qtp-sequencing.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py qtp-sequencing start_qtp_sequencing /qtp-sequencing +cd / && python trigger.py start_qtp_sequencing tail -f /dev/null diff --git a/Makefile b/Makefile index 9c87dee..dcba2f5 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh +.built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh Images/qtp-sequencing/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From 3b534abc4ff26bac8eda19defe6b8027cbc03ef3 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 12:40:49 +0200 Subject: [PATCH 160/287] "install" pigz --- Images/qp-target-gene/qp-target-gene.dockerfile | 3 +++ Images/qtp-sequencing/qtp-sequencing.dockerfile | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index 2448f5c..15367d8 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -94,6 +94,9 @@ RUN pip2 install --no-cache-dir /wheels/* \ && rm -rf rm -rf `find /usr/local/lib/python2.7/site-packages -type d -name "tests" | grep -v numpy` COPY --from=builder /opt/conda/envs/qp-target-gene/lib/libpython2.7.so.1.0 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 +# "install" pigz +COPY --from=builder /opt/conda/envs/qp-target-gene/bin/pigz /usr/local/bin/ + COPY start_qp-target-gene.sh . RUN chmod 755 start_qp-target-gene.sh diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index d5712e5..c5012b1 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -67,9 +67,14 @@ COPY --from=builder /wheels /wheels RUN pip install --no-cache-dir /wheels/* \ && rm -rf rm -rf `find /usr/local/lib/python3.9/site-packages -type d -name "tests" | grep -v numpy` -# # install tornado based trigger layer in base environment -# RUN pip install -U pip -# RUN pip install tornado +# "install" https://github.com/alastair-droop/fqtools +COPY --from=builder /opt/conda/envs/qtp-sequencing/bin/fqtools /usr/local/bin/fqtools +COPY --from=builder /opt/conda/envs/qtp-sequencing/lib/libhts.so.1.22.1 /lib/x86_64-linux-gnu/libhts.so.3 +COPY --from=builder /opt/conda/envs/qtp-sequencing/lib/libdeflate.so.0 /lib/x86_64-linux-gnu/ + +# "install" pigz +COPY --from=builder /opt/conda/envs/qtp-sequencing/bin/pigz /usr/local/bin/ + COPY trigger_noconda.py /trigger.py # WORKDIR / From 8598ae71ffddfd414758ed992c5d227dcce87fab Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 12:49:25 +0200 Subject: [PATCH 161/287] also build qtp-sequencing docker container --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 54db067..272881f 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene"] + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing"] runs-on: ubuntu-latest steps: - name: Checkout repository From 946ed4183fe8fb95c43f6299f52b8ed4afa93c15 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 13:16:21 +0200 Subject: [PATCH 162/287] use a much smaller base for nginx --- .github/workflows/buildContainer.yaml | 2 +- Images/nginx/nginx.dockerfile | 82 ++------------------------- Images/nginx/requirements.txt | 1 + Images/nginx/start_nginx.sh | 7 ++- 4 files changed, 11 insertions(+), 81 deletions(-) create mode 100644 Images/nginx/requirements.txt diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 272881f..43e65e5 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing"] + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx"] runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/Images/nginx/nginx.dockerfile b/Images/nginx/nginx.dockerfile index 9b5a51f..c014db0 100644 --- a/Images/nginx/nginx.dockerfile +++ b/Images/nginx/nginx.dockerfile @@ -1,83 +1,11 @@ -FROM ubuntu:22.04 +FROM yspreen/nginx -ARG MINIFORGE_VERSION=24.1.2-0 -ARG MODZIP_VERSION=1.3.0 -ARG NGINX_VERSION=1.26.0 - -ENV CONDA_DIR=/opt/conda -ENV PATH=${CONDA_DIR}/bin:${PATH} - -RUN apt-get -y update -RUN apt-get -y install \ - git \ - wget \ - libpcre2-dev \ - libxslt-dev \ - libgd-dev \ - libssl-dev -RUN apt-get -y install build-essential -# install miniforge3 for "conda" -# see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile -RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-x86_64.sh -O /tmp/miniforge3.sh && \ - /bin/bash /tmp/miniforge3.sh -b -p ${CONDA_DIR} && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> /etc/skel/.bashrc && \ - echo ". ${CONDA_DIR}/etc/profile.d/conda.sh && conda activate base" >> ~/.bashrc \ - conda init -RUN conda create --quiet --yes -n nginx - -SHELL ["conda", "run", "-n", "nginx", "/bin/bash", "-c"] - -RUN wget https://github.com/evanmiller/mod_zip/archive/refs/tags/${MODZIP_VERSION}.tar.gz -O /usr/local/src/mod_zip-${MODZIP_VERSION}.tar.gz -RUN cd /usr/local/src/ && tar xzvf mod_zip-${MODZIP_VERSION}.tar.gz -RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-${NGINX_VERSION}.tar.gz -O /usr/local/src/nginx-${NGINX_VERSION}.tar.gz -RUN cd /usr/local/src/ && tar xzvf nginx-${NGINX_VERSION}.tar.gz -# fix include for the iconv header -RUN sed "s|^#include |#include \"/usr/include/iconv.h\"|" -i /usr/local/src/mod_zip-${MODZIP_VERSION}/ngx_http_zip_file.c -# ensure runtime library paths are correct and openssl headers can be found at compile time -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && ./auto/configure \ - --http-log-path=var/log/nginx/access.log \ - --error-log-path=var/log/nginx/error.log \ - --pid-path=var/run/nginx/nginx.pid \ - --lock-path=var/run/nginx/nginx.lock \ - --http-client-body-temp-path=var/tmp/nginx/client \ - --http-proxy-temp-path=var/tmp/nginx/proxy \ - --http-fastcgi-temp-path=var/tmp/nginx/fastcgi \ - --http-scgi-temp-path=var/tmp/nginx/scgi \ - --http-uwsgi-temp-path=var/tmp/nginx/uwsgi \ - --sbin-path=sbin/nginx \ - --conf-path=etc/nginx/nginx.conf \ - --modules-path=lib/nginx/modules \ - --with-threads \ - --with-http_ssl_module \ - --with-http_v2_module \ - --with-http_realip_module \ - --with-http_addition_module \ - --with-http_sub_module \ - --with-http_gunzip_module \ - --with-http_gzip_static_module \ - --with-http_auth_request_module \ - --with-http_secure_link_module \ - --with-http_stub_status_module \ - --with-http_xslt_module=dynamic \ - --with-stream=dynamic \ - --with-http_image_filter_module=dynamic \ - --with-pcre \ - --with-pcre-jit \ - --with-cc-opt=" -I $CONDA_DIR/envs/qiita/include/openssl " \ - --with-ld-opt="" \ - --prefix=/usr/local \ - --add-module=/usr/local/src/mod_zip-${MODZIP_VERSION} \ - --with-ld-opt=" -Wl,-rpath,$CONDA_DIR/envs/qiita/lib " -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make -j 10 -RUN cd /usr/local/src/nginx-release-${NGINX_VERSION} && make install - -COPY nginx_qiita.conf . -COPY start_nginx.sh . +COPY nginx_qiita.conf / +COPY start_nginx.sh / RUN chmod 777 nginx_qiita.conf RUN chmod 777 start_nginx.sh -RUN mkdir /var/log/nginx +RUN mkdir -p /var/log/nginx -#ENTRYPOINT ["/bin/bash", "-l", "-c" ] -CMD ["conda", "run", "-n", "nginx", "./start_nginx.sh"] \ No newline at end of file +CMD ["nginx", "/start_nginx.sh"] diff --git a/Images/nginx/requirements.txt b/Images/nginx/requirements.txt new file mode 100644 index 0000000..bcbe69d --- /dev/null +++ b/Images/nginx/requirements.txt @@ -0,0 +1 @@ +empty! \ No newline at end of file diff --git a/Images/nginx/start_nginx.sh b/Images/nginx/start_nginx.sh index a95a1a1..2906803 100644 --- a/Images/nginx/start_nginx.sh +++ b/Images/nginx/start_nginx.sh @@ -1,4 +1,5 @@ -#!/bin/bash -mkdir -p /opt/conda/envs/nginx/var/run/nginx/ /usr/local/var/tmp/nginx/ +#!/bin/sh +mkdir -p /var/run/nginx/ /usr/local/var/tmp/nginx/ -nginx -c /qiita_configuration/nginx_qiita.conf +nginx -t -c /qiita_configuration/nginx_qiita.conf +nginx -c /qiita_configuration/nginx_qiita.conf From 26d172897f71987d90cbc42939c786a14f7ae8bc Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 13:17:55 +0200 Subject: [PATCH 163/287] forgot to add a version line --- Images/nginx/nginx.dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Images/nginx/nginx.dockerfile b/Images/nginx/nginx.dockerfile index c014db0..c2ea3cd 100644 --- a/Images/nginx/nginx.dockerfile +++ b/Images/nginx/nginx.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.08.28 + FROM yspreen/nginx COPY nginx_qiita.conf / From 38e5ffd0132c50e05c5b9c8ce0a1af812ed5f085 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 28 Aug 2025 13:20:20 +0200 Subject: [PATCH 164/287] copy file to correct location --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 43e65e5..21e0745 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -29,7 +29,7 @@ jobs: run: | VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/${{ matrix.plugin }}/requirements.txt . + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt From acc02c4163e04ea8a0b4e4bca0de61705a672c45 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 29 Aug 2025 09:31:43 +0200 Subject: [PATCH 165/287] qiime2 tiny did not work out, since their qz* are too new for other plugins :-/ Falling back to a more laborsome qiime2 core version, where only select plugins get installedd --- Images/qtp-biom/qtp-biom.dockerfile | 49 +++++++++++++++++++---------- Images/qtp-biom/requirements.txt | 3 +- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 0bb9df4..8f2fcd3 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -1,9 +1,9 @@ -# VERSION: 2025.08.26 +# VERSION: 2025.08.29 FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 -ARG QIITARELEASE=2025.7 +ARG QIIME2RELEASE=2022.8 ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} @@ -36,11 +36,22 @@ RUN conda install tornado COPY trigger.py /trigger.py # Download qtp-biom yaml -RUN wget https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/${QIITARELEASE}/tiny/released/qiime2-tiny-ubuntu-latest-conda.yml -RUN echo "- q2-feature-table" >> qiime2-tiny-ubuntu-latest-conda.yml -RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/${QIITARELEASE}/amplicon/released/\n- conda-forge|" qiime2-tiny-ubuntu-latest-conda.yml +# RUN wget https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/${QIIME2RELEASE}/tiny/released/qiime2-tiny-ubuntu-latest-conda.yml +RUN wget https://data.qiime2.org/distro/core/qiime2-${QIIME2RELEASE}-py38-linux-conda.yml + +RUN sed -n '/channels/,/dependencies/p' qiime2-2022.8-py38-linux-conda.yml > tinyq2.yml && \ + echo " - q2-metadata=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-mystery-stew=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-types=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2cli=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2templates=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - qiime2" >> tinyq2.yml && \ + echo " - q2-feature-table=${QIIME2RELEASE}" >> tinyq2.yml + +# # #RUN echo "- q2-feature-table" >> qiime2-${QIIME2RELEASE}-py38-linux-conda.yml +# # #RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/${QIIME2RELEASE}/passed/core/\n- conda-forge|" qiime2-${QIIME2RELEASE}-py38-linux-conda.yml # Create conda env -RUN conda env create --quiet -n qtp-biom --file qiime2-tiny-ubuntu-latest-conda.yml +RUN conda env create --quiet -n qtp-biom --file tinyq2.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] @@ -92,32 +103,35 @@ WORKDIR / # prepare for runtime stage # WORKDIR / RUN pip uninstall pip-system-certs -y -RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-feature-table.git -RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-metadata.git -RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-mystery-stew.git -RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2-types.git -RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2cli.git -RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/q2templates.git -RUN git clone -b Release-${QIITARELEASE} https://github.com/qiime2/qiime2.git +RUN repo=q2-feature-table; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-metadata; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-mystery-stew; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-types; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2cli; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2templates; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=qiime2; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.3.tar.gz | tar -xz --strip-components=1 -C /$repo COPY requirements.txt ./requirements.txt +RUN conda install cython RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt +RUN pip install iow CMD ["./start_qtp-biom.sh"] # ========================== # Stage 2: Runtime # ========================== -FROM python:3.10-slim +FROM python:3.8-slim # python package compile in build stage COPY --from=builder /wheels /wheels RUN pip install --no-cache-dir /wheels/* \ - && rm -rf rm -rf `find /usr/local/lib/python3.10/site-packages -type d -name "tests" | grep -v numpy` + && rm -rf rm -rf `find /usr/local/lib/python3.8/site-packages -type d -name "tests" | grep -v numpy` # ^^ 788MB -COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.10/site-packages/bp /usr/local/lib/python3.10/site-packages/bp +COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/bp /usr/local/lib/python3.8/site-packages/bp +RUN ln -s /usr/local/lib/python3.8/site-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 # install tornado based trigger layer in base environment RUN pip install -U --no-cache-dir tornado @@ -150,6 +164,9 @@ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN /usr/local/bin/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf +# fix an pandas deprecation issue, i.e. patch q2templates code +RUN sed -i "s/'display.max_colwidth', -1/'display.max_colwidth', None/" /usr/local/lib/python3.8/site-packages/q2templates/util.py + # remove conda command from tigger.py # RUN sed -i "s|source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s;||" /trigger.py && sed -i "s|conda_env_name, ||" /trigger.py diff --git a/Images/qtp-biom/requirements.txt b/Images/qtp-biom/requirements.txt index a32d2ee..3c7bb3d 100644 --- a/Images/qtp-biom/requirements.txt +++ b/Images/qtp-biom/requirements.txt @@ -22,7 +22,8 @@ jinja2 ijson pyhmmer frictionless -numpy==1.26.4 +numpy +iow -e /qtp-biom -e /qiita-files From d9f70292eb1fb8ad24f1d4024efbb310b42afdb0 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 29 Aug 2025 09:45:25 +0200 Subject: [PATCH 166/287] code style --- Images/qp-target-gene/qp-target-gene.dockerfile | 2 +- Images/qtp-sequencing/qtp-sequencing.dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index 15367d8..90548dd 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -3,7 +3,7 @@ # ========================== # Stage 1: Build wheels # ========================== -FROM ubuntu:24.04 as builder +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index c5012b1..ae2640d 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -3,7 +3,7 @@ # ========================== # Stage 1: Build wheels (~5.8 GB) # ========================== -FROM ubuntu:24.04 as builder +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 From 826a413208a7c228b444fb2a3532de3b8d28a7d1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 29 Aug 2025 12:09:23 +0200 Subject: [PATCH 167/287] speed up conda resolving --- Images/qtp-biom/qtp-biom.dockerfile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 8f2fcd3..73d9c6c 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -40,18 +40,18 @@ COPY trigger.py /trigger.py RUN wget https://data.qiime2.org/distro/core/qiime2-${QIIME2RELEASE}-py38-linux-conda.yml RUN sed -n '/channels/,/dependencies/p' qiime2-2022.8-py38-linux-conda.yml > tinyq2.yml && \ - echo " - q2-metadata=${QIIME2RELEASE}" >> tinyq2.yml && \ - echo " - q2-mystery-stew=${QIIME2RELEASE}" >> tinyq2.yml && \ - echo " - q2-types=${QIIME2RELEASE}" >> tinyq2.yml && \ - echo " - q2cli=${QIIME2RELEASE}" >> tinyq2.yml && \ - echo " - q2templates=${QIIME2RELEASE}" >> tinyq2.yml && \ - echo " - qiime2" >> tinyq2.yml && \ - echo " - q2-feature-table=${QIIME2RELEASE}" >> tinyq2.yml + echo " - q2-metadata=${QIIME2RELEASE}.0" >> tinyq2.yml && \ + echo " - q2-mystery-stew=${QIIME2RELEASE}.0" >> tinyq2.yml && \ + echo " - q2-types=${QIIME2RELEASE}.0" >> tinyq2.yml && \ + echo " - q2cli=${QIIME2RELEASE}.1" >> tinyq2.yml && \ + echo " - q2templates=${QIIME2RELEASE}.0" >> tinyq2.yml && \ + echo " - qiime2=${QIIME2RELEASE}.1" >> tinyq2.yml && \ + echo " - q2-feature-table=${QIIME2RELEASE}.0" >> tinyq2.yml # # #RUN echo "- q2-feature-table" >> qiime2-${QIIME2RELEASE}-py38-linux-conda.yml # # #RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/${QIIME2RELEASE}/passed/core/\n- conda-forge|" qiime2-${QIIME2RELEASE}-py38-linux-conda.yml # Create conda env -RUN conda env create --quiet -n qtp-biom --file tinyq2.yml +RUN conda config --set channel_priority strict && conda env create --quiet -n qtp-biom --file tinyq2.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] From 98a65da1ab22a04dd27b46715bd28ad6da98bdf0 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 29 Aug 2025 12:10:05 +0200 Subject: [PATCH 168/287] still big, but reduced qiime2 --- .../qtp-visualization.dockerfile | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile index f66612d..e3f0766 100644 --- a/Images/qtp-visualization/qtp-visualization.dockerfile +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -1,6 +1,7 @@ -FROM ubuntu:24.04 +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 +ARG QIIME2RELEASE=2023.5 ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} @@ -29,10 +30,19 @@ RUN conda install tornado COPY trigger.py /trigger.py # Download qiime2 yaml (make sure to use a qiime2 version that is able to visualize qiime artifacts of the correct version) -RUN wget --quiet https://data.qiime2.org/distro/core/qiime2-2023.5-py38-linux-conda.yml +RUN wget --quiet https://data.qiime2.org/distro/core/qiime2-${QIIME2RELEASE}-py38-linux-conda.yml + +RUN sed -n '/channels/,/dependencies/p' qiime2-${QIIME2RELEASE}-py38-linux-conda.yml > tinyq2.yml && \ + echo " - q2-metadata=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-mystery-stew=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-types=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2cli=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2templates=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - typeguard=2.13.3" >> tinyq2.yml && \ + echo " - qiime2" >> tinyq2.yml # Create conda env -RUN conda env create --name qtp-visualization -y --file qiime2-2023.5-py38-linux-conda.yml +RUN conda config --set channel_priority strict && conda env create --name qtp-visualization -y --file tinyq2.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-visualization", "/bin/bash", "-c"] @@ -41,17 +51,22 @@ ENV LC_ALL=C.UTF-8 ENV LANG=C.UTF-8 RUN pip install -U pip -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +#RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py +RUN cd qiita_client && pip install --no-cache-dir . + +#RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone -b master https://github.com/jlab/qiita-files.git +RUN cd /qiita-files && pip install -e . -v + RUN git clone https://github.com/qiita-spots/qtp-visualization.git -WORKDIR qtp-visualization +WORKDIR /qtp-visualization +RUN sed -i "s|'qiita_client', 'click >= 3.3', 'qiime2'|'click >= 3.3'|" setup.py RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg - WORKDIR / COPY start_qtp-visualization.sh . @@ -72,3 +87,9 @@ RUN /qtp-visualization/scripts/configure_visualization_types --env-script "true" RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-visualization/" /unshared_plugins/*.conf CMD ["./start_qtp-visualization.sh"] + +# # ========================== +# # Stage 2: Runtime +# # ========================== +# FROM python:3.8-slim + From 6fae6b5bfd969c1600b823ed014e829f1880480e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 29 Aug 2025 13:59:40 +0200 Subject: [PATCH 169/287] shrink qtp-visualization --- .github/workflows/buildContainer.yaml | 2 +- .../qtp-visualization.dockerfile | 44 ++++++++++++++----- Images/qtp-visualization/requirements.txt | 30 +++++++++++++ .../start_qtp-visualization.sh | 2 +- Makefile | 2 +- 5 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 Images/qtp-visualization/requirements.txt diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 21e0745..5eecef1 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx"] + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization"] runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile index e3f0766..5e82a88 100644 --- a/Images/qtp-visualization/qtp-visualization.dockerfile +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.08.29 + FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 @@ -69,27 +71,49 @@ RUN pip install pip-system-certs WORKDIR / +RUN repo=q2-metadata; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-mystery-stew; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-types; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2cli; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2templates; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=qiime2; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo + +COPY requirements.txt ./requirements.txt +RUN conda install cython +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt +RUN pip install iow + + + +# ========================== +# Stage 2: Runtime +# ========================== +FROM python:3.8-slim + +# python package compile in build stage +COPY --from=builder /wheels /wheels + +RUN pip install --no-cache-dir /wheels/* \ + && rm -rf rm -rf `find /usr/local/lib/python3.8/site-packages -type d -name "tests" | grep -v numpy` + COPY start_qtp-visualization.sh . RUN chmod 755 start_qtp-visualization.sh RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ +COPY trigger_noconda.py /trigger.py + ## Export cert and config filepaths COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem -#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN chmod u+x /qtp-visualization/scripts/configure_visualization_types /qtp-visualization/scripts/start_visualization_types +RUN chmod u+x /usr/local/bin/configure_visualization_types /usr/local/bin/start_visualization_types COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /qtp-visualization/scripts/configure_visualization_types --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +# qiime2 expects to have a CONDA_PREFIX set, see https://github.com/qiime2/qiime2/blob/812fd09cf80b4ed76c1f39827ae2dba729448436/qiime2/sdk/parallel_config.py#L30 +ENV CONDA_PREFIX=/usr/local +RUN configure_visualization_types --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-visualization/" /unshared_plugins/*.conf -CMD ["./start_qtp-visualization.sh"] - -# # ========================== -# # Stage 2: Runtime -# # ========================== -# FROM python:3.8-slim - +CMD ["./start_qtp-visualization.sh"] \ No newline at end of file diff --git a/Images/qtp-visualization/requirements.txt b/Images/qtp-visualization/requirements.txt new file mode 100644 index 0000000..15ececc --- /dev/null +++ b/Images/qtp-visualization/requirements.txt @@ -0,0 +1,30 @@ +-e /q2-metadata +-e /q2-mystery-stew +-e /q2-types +-e /q2cli +-e /q2templates +-e /qiime2 + +tornado +pip-system-certs +pyyaml +decorator +tzlocal +bibtexparser +psutil +flufl.lock +parsl +appdirs +tomlkit +scikit-bio +rnanorm +seaborn +jinja2 +ijson +pyhmmer +frictionless +numpy + +-e /qtp-visualization +-e /qiita-files +-e /qiita_client \ No newline at end of file diff --git a/Images/qtp-visualization/start_qtp-visualization.sh b/Images/qtp-visualization/start_qtp-visualization.sh index f3aeebe..e5a4c14 100644 --- a/Images/qtp-visualization/start_qtp-visualization.sh +++ b/Images/qtp-visualization/start_qtp-visualization.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py qtp-visualization start_visualization_types /qtp-visualization +cd / && python trigger.py start_visualization_types tail -f /dev/null diff --git a/Makefile b/Makefile index dcba2f5..8f9a537 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qtp-visualization: Images/qtp-visualization/qtp-visualization.dockerfile Images/qtp-visualization/start_qtp-visualization.sh +.built_image_qtp-visualization: Images/qtp-visualization/qtp-visualization.dockerfile Images/qtp-visualization/start_qtp-visualization.sh Images/qtp-visualization/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From 47ee214f1413ec8ca99f0589a9819c80b89210d5 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 29 Aug 2025 14:04:37 +0200 Subject: [PATCH 170/287] relax channel prios --- Images/qtp-biom/qtp-biom.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 73d9c6c..b067ad0 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -51,7 +51,7 @@ RUN sed -n '/channels/,/dependencies/p' qiime2-2022.8-py38-linux-conda.yml > tin # # #RUN echo "- q2-feature-table" >> qiime2-${QIIME2RELEASE}-py38-linux-conda.yml # # #RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/${QIIME2RELEASE}/passed/core/\n- conda-forge|" qiime2-${QIIME2RELEASE}-py38-linux-conda.yml # Create conda env -RUN conda config --set channel_priority strict && conda env create --quiet -n qtp-biom --file tinyq2.yml +RUN conda env create --quiet -n qtp-biom --file tinyq2.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] From 008273acf9c01e0bfab191965d4728002fdd4772 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 1 Sep 2025 16:33:23 +0200 Subject: [PATCH 171/287] strict but no sub-version --- Images/qtp-biom/qtp-biom.dockerfile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index b067ad0..8088d2e 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -40,18 +40,18 @@ COPY trigger.py /trigger.py RUN wget https://data.qiime2.org/distro/core/qiime2-${QIIME2RELEASE}-py38-linux-conda.yml RUN sed -n '/channels/,/dependencies/p' qiime2-2022.8-py38-linux-conda.yml > tinyq2.yml && \ - echo " - q2-metadata=${QIIME2RELEASE}.0" >> tinyq2.yml && \ - echo " - q2-mystery-stew=${QIIME2RELEASE}.0" >> tinyq2.yml && \ - echo " - q2-types=${QIIME2RELEASE}.0" >> tinyq2.yml && \ - echo " - q2cli=${QIIME2RELEASE}.1" >> tinyq2.yml && \ - echo " - q2templates=${QIIME2RELEASE}.0" >> tinyq2.yml && \ - echo " - qiime2=${QIIME2RELEASE}.1" >> tinyq2.yml && \ - echo " - q2-feature-table=${QIIME2RELEASE}.0" >> tinyq2.yml + echo " - q2-metadata=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-mystery-stew=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-types=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2cli=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2templates=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - qiime2=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-feature-table=${QIIME2RELEASE}" >> tinyq2.yml # # #RUN echo "- q2-feature-table" >> qiime2-${QIIME2RELEASE}-py38-linux-conda.yml # # #RUN sed -i "s|- conda-forge|- https://packages.qiime2.org/qiime2/${QIIME2RELEASE}/passed/core/\n- conda-forge|" qiime2-${QIIME2RELEASE}-py38-linux-conda.yml # Create conda env -RUN conda env create --quiet -n qtp-biom --file tinyq2.yml +RUN conda config --set channel_priority strict && conda env create --quiet -n qtp-biom --file tinyq2.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] From 24abc2798172c80b98ac7ef8c03a92c704cf595f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 1 Sep 2025 16:43:01 +0200 Subject: [PATCH 172/287] use master branch for qiita-files and qiita-client --- Images/qtp-biom/qtp-biom.dockerfile | 5 ++--- .../qtp-job-output-folder.dockerfile | 2 +- Images/qtp-sequencing/qtp-sequencing.dockerfile | 2 +- Images/qtp-visualization/qtp-visualization.dockerfile | 11 ++++------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 8088d2e..9c8942a 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -58,12 +58,11 @@ SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-biom", "/bin/bash", "-c"] RUN pip install -U pip # RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git -RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py +RUN git clone -b master https://github.com/qiita-spots/qiita_client.git RUN cd qiita_client && pip install --no-cache-dir . # RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip -RUN git clone -b migrate_py310 https://github.com/jlab/qiita-files.git +RUN git clone -b master https://github.com/qiita-spots/qiita-files.git # COPY ./qiita-files /qiita-files RUN cd /qiita-files && pip install -e . -v RUN git clone https://github.com/qiita-spots/qtp-biom.git diff --git a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile index a4ee767..0d92840 100644 --- a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile +++ b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile @@ -36,7 +36,7 @@ SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-job-output-folder", "/bin/bash RUN pip install -U pip RUN git clone https://github.com/qiita-spots/qtp-job-output-folder.git -WORKDIR qtp-job-output-folder +WORKDIR /qtp-job-output-folder RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index ae2640d..23acc0e 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -36,7 +36,7 @@ SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-sequencing", "/bin/bash", "-c" RUN pip install -U pip #RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN git clone -b master https://github.com/qiita-spots/qiita_client.git RUN cd qiita_client && pip install --no-cache-dir . # RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile index 5e82a88..ca8e51d 100644 --- a/Images/qtp-visualization/qtp-visualization.dockerfile +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -28,8 +28,6 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ # install tornado based trigger layer in base environment RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py # Download qiime2 yaml (make sure to use a qiime2 version that is able to visualize qiime artifacts of the correct version) RUN wget --quiet https://data.qiime2.org/distro/core/qiime2-${QIIME2RELEASE}-py38-linux-conda.yml @@ -54,12 +52,11 @@ ENV LANG=C.UTF-8 RUN pip install -U pip #RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git -RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py +RUN git clone -b master https://github.com/qiita-spots/qiita_client.git RUN cd qiita_client && pip install --no-cache-dir . #RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip -RUN git clone -b master https://github.com/jlab/qiita-files.git +RUN git clone -b master https://github.com/qiita-spots/qiita-files.git RUN cd /qiita-files && pip install -e . -v RUN git clone https://github.com/qiita-spots/qtp-visualization.git @@ -79,9 +76,9 @@ RUN repo=q2templates; mkdir -p /$repo && wget -O- https://github.com/qiime2/$rep RUN repo=qiime2; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo COPY requirements.txt ./requirements.txt -RUN conda install cython +# RUN conda install cython RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt -RUN pip install iow +# RUN pip install iow From 3c0f4cba0fbb85878238e42d55f7deaadbe758f1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 1 Sep 2025 16:47:47 +0200 Subject: [PATCH 173/287] use master --- Images/qp-deblur/qp-deblur.dockerfile | 2 +- Images/qp-target-gene/qp-target-gene.dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 5029339..0d24d91 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -37,7 +37,7 @@ SHELL ["conda", "run", "-p", "/opt/conda/envs/deblur", "/bin/bash", "-c"] ENV LC_ALL=C.UTF-8 ENV LANG=C.UTF-8 -RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN git clone -b master https://github.com/qiita-spots/qiita_client.git RUN sed -i "s/f'Entered BaseQiitaPlugin._register_command({command.name})'/'Entered BaseQiitaPlugin._register_command(%s)' % command.name/" qiita_client/qiita_client/plugin.py RUN cd qiita_client && pip install --no-cache-dir . diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index 90548dd..d35bc87 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -44,7 +44,7 @@ RUN python2.7 get-pip2.7.py --force-reinstall RUN pip install -U pip #RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN git clone -b uncouplePlugins https://github.com/jlab/qiita_client.git +RUN git clone -b master https://github.com/qiita-spots/qiita_client.git RUN cd qiita_client && pip install --no-cache-dir . RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip From 9a2c9e5c66315e41e55d3d85eb9271035f7652a9 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:22:39 +0200 Subject: [PATCH 174/287] trigger qiita image build --- .github/workflows/buildContainer.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 5eecef1..8ae2e7c 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,8 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization"] + plugin: ["qp-deblur", #, "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", "qtp-diversity", + "qiita"] runs-on: ubuntu-latest steps: - name: Checkout repository @@ -30,6 +31,7 @@ jobs: VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . + cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt From b4daee77b91aadb26e87c15672d362bdd08d4dce Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:23:47 +0200 Subject: [PATCH 175/287] add empty file --- Images/qiita/requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Images/qiita/requirements.txt diff --git a/Images/qiita/requirements.txt b/Images/qiita/requirements.txt new file mode 100644 index 0000000..e69de29 From fcf8292e73b09e0a885f56b35534f1b6cf5ccc79 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:29:11 +0200 Subject: [PATCH 176/287] add version tags --- .github/workflows/buildContainer.yaml | 3 ++- Images/plugin_collector/plugin_collector.dockerfile | 2 ++ Images/qiita/qiita.dockerfile | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 8ae2e7c..d90fef7 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -10,7 +10,7 @@ jobs: strategy: matrix: plugin: ["qp-deblur", #, "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", "qtp-diversity", - "qiita"] + "qiita", "plugin_collector"] runs-on: ubuntu-latest steps: - name: Checkout repository @@ -32,6 +32,7 @@ jobs: echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . + cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/startup_plugin_collector.sh Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt diff --git a/Images/plugin_collector/plugin_collector.dockerfile b/Images/plugin_collector/plugin_collector.dockerfile index baecfdf..bb00a66 100644 --- a/Images/plugin_collector/plugin_collector.dockerfile +++ b/Images/plugin_collector/plugin_collector.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.09.02 + FROM ubuntu:24.04 RUN apt-get -y update diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index 79f126c..53f5fe4 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.09.02 + FROM ubuntu:24.04 ARG MINIFORGE_VERSION=24.1.2-0 From 485ac9d1b0f9e84c4100039252fc4bf538eee65b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:29:24 +0200 Subject: [PATCH 177/287] add req file --- Images/plugin_collector/requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Images/plugin_collector/requirements.txt diff --git a/Images/plugin_collector/requirements.txt b/Images/plugin_collector/requirements.txt new file mode 100644 index 0000000..e69de29 From d51972298fe7c92cb78af60859a1bcb88589188d Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:32:13 +0200 Subject: [PATCH 178/287] forgot target --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index d90fef7..b27b6f6 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -32,7 +32,7 @@ jobs: echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . - cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/startup_plugin_collector.sh Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf + cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/startup_plugin_collector.sh Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt From cad5c43eec243e654dd356aba8b43ba0f7a9b4a3 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:36:50 +0200 Subject: [PATCH 179/287] normalize name --- Images/plugin_collector/plugin_collector.dockerfile | 6 +++--- ...tartup_plugin_collector.sh => start_plugin_collector.sh} | 0 compose.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename Images/plugin_collector/{startup_plugin_collector.sh => start_plugin_collector.sh} (100%) diff --git a/Images/plugin_collector/plugin_collector.dockerfile b/Images/plugin_collector/plugin_collector.dockerfile index bb00a66..799da21 100644 --- a/Images/plugin_collector/plugin_collector.dockerfile +++ b/Images/plugin_collector/plugin_collector.dockerfile @@ -11,7 +11,7 @@ RUN apt-get -y --fix-missing install \ COPY collect_configs.py /collect_configs.py COPY fix_test_db.py /fix_test_db.py -COPY startup_plugin_collector.sh /startup_plugin_collector.sh -RUN chmod u+x /startup_plugin_collector.sh +COPY start_plugin_collector.sh /start_plugin_collector.sh +RUN chmod u+x /start_plugin_collector.sh -CMD /startup_plugin_collector.sh \ No newline at end of file +CMD /start_plugin_collector.sh \ No newline at end of file diff --git a/Images/plugin_collector/startup_plugin_collector.sh b/Images/plugin_collector/start_plugin_collector.sh similarity index 100% rename from Images/plugin_collector/startup_plugin_collector.sh rename to Images/plugin_collector/start_plugin_collector.sh diff --git a/compose.yaml b/compose.yaml index b0d0e1b..d9151ef 100644 --- a/compose.yaml +++ b/compose.yaml @@ -345,7 +345,7 @@ services: condition: service_started environment: - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" - command: ['/startup_plugin_collector.sh'] + command: ['/start_plugin_collector.sh'] networks: qiita-net: From 4c22e1daa739243263fbbf9037d898afca836f05 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:37:20 +0200 Subject: [PATCH 180/287] remove duplicate --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index b27b6f6..79c45cd 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -32,7 +32,7 @@ jobs: echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . - cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/startup_plugin_collector.sh Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . + cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt From ebb93a7b3950390793a3369e077dbd324939b000 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:52:42 +0200 Subject: [PATCH 181/287] add compose --- .github/workflows/buildContainer.yaml | 9 + compose_github.yaml | 306 ++++++++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 compose_github.yaml diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 79c45cd..6c102c1 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -43,3 +43,12 @@ jobs: push: true file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} + + - name: Make tinqiita targets + run: | + make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre + + - name: Run docker compose + uses: hoverkraft-tech/compose-action@v2.0.1 + with: + compose-file: "compose_github.yaml" \ No newline at end of file diff --git a/compose_github.yaml b/compose_github.yaml new file mode 100644 index 0000000..54756e1 --- /dev/null +++ b/compose_github.yaml @@ -0,0 +1,306 @@ +name: tinqiita + +services: + qiita-db: + image: postgres:15 + container_name: qiita-db + hostname: qiita-db + restart: no + env_file: + - ./environments/qiita_db.env + environment: + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + volumes: + - './environments/qiita-db-init.sh:/docker-entrypoint-initdb.d/qiita-db-init.sh' + - 'postgres-data:/var/lib/postgresql/data' + - server-plugin-configs:/qiita_plugins + networks: + - qiita-net + ports: + - "15432:5432" + + qiita-initialize-db: + image: janssenlab/qiita:latest + command: ['/start_qiita-initDB.sh'] + depends_on: + - qiita-db + env_file: + - './environments/qiita.env' + environment: + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + volumes: + - qiita-data:/qiita_data + - server-plugin-configs:/qiita_plugins + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r + networks: + - qiita-net + + qiita: + image: janssenlab/qiita:latest + build: # image wird hier direkt gebaut + context: ./Images/qiita + dockerfile: Dockerfile + command: ['/start_qiita.sh'] # executes bash script inside the container + # entrypoint: /bin/bash + # stdin_open: true + # tty: true + # ports: + # - "21174:21174" # wihtout nginx + # - 127.0.0.1:8383:8383 #damit bur ich dran komme + restart: no + depends_on: + - qiita-worker + env_file: + - './environments/qiita.env' + environment: + #- QIITA_ROOTCA_CERT=/qiita_certificates/stefan_rootca.crt # does not seem to have effect if not set in config file + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - PORT=21174 + - MASTER=--master + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + volumes: + - qiita-data:/qiita_data + - ./logs:/logs + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r + - server-plugin-configs:/qiita_plugins + - ./references/qiita_server_certificates:/qiita_certificates + networks: + - qiita-net + ports: + - "21174:21174" + + qiita-worker: + image: janssenlab/qiita:latest + build: # image wird hier direkt gebaut + context: ./Images/qiita + dockerfile: Dockerfile + command: ['./start_qiita.sh'] # executes bash script inside the container + # entrypoint: /bin/bash + # stdin_open: true + # tty: true + # ports: + # - "21174:21174" # wihtout nginx + # - 127.0.0.1:8383:8383 #damit bur ich dran komme + restart: no + depends_on: + redis: + condition: service_started + plugin-collector: + condition: service_completed_successfully + env_file: + - './environments/qiita.env' + environment: + #- QIITA_ROOTCA_CERT=/qiita_certificates/stefan_rootca.crt # does not seem to have effect if not set in config file + - QIITA_CONFIG_FP=/qiita_configurations/qiita_server.cfg + - PORT=21175 + - MASTER= + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + volumes: + - qiita-data:/qiita_data + - ./logs:/logs + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r + - server-plugin-configs:/qiita_plugins + - ./references/qiita_server_certificates:/qiita_certificates + networks: + - qiita-net + deploy: + replicas: 3 + + redis: + image: redis:latest + restart: no + command: > + sh -c "redis-server --port 7777 && + redis-server --port 6379" + volumes: + - qiita-data:/qiita + - ./logs:/logs + networks: + - qiita-net + + nginx: + image: janssenlab/nginx:latest + build: + context: ./Images/nginx + dockerfile: Dockerfile + ports: + - "8383:8383" + command: ['./start_nginx.sh'] + restart: no + depends_on: + - qiita + volumes: + - qiita-data:/qiita_data + - ./logs:/logs + - ./Images/nginx/nginx_qiita.conf:/qiita_configuration/nginx_qiita.conf + - ./references/qiita_server_certificates:/qiita_certificates + networks: + - qiita-net + + # qtp-biom: + # image: local-qtp-biom:latest + # command: ['./start_qtp-biom.sh'] + # # network_mode: host + # # stdin_open: true + # # tty: true + # restart: no + # volumes: + # - qiita-data:/qiita_data + # - ./references/qiita_server_certificates:/qiita_server_certificates + # - ./src/qtp-biom:/qtp-biom:U + # environment: + # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + # networks: + # - qiita-net + + # qtp-sequencing: + # image: local-qtp-sequencing:latest + # command: ['./start_qtp-sequencing.sh'] + # # network_mode: host + # # stdin_open: true + # # tty: true + # restart: no + # volumes: + # - qiita-data:/qiita_data + # - ./references/qiita_server_certificates:/qiita_server_certificates + # environment: + # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + # networks: + # - qiita-net + + # qp-target-gene: + # image: local-qp-target-gene:latest + # command: ['./start_qp-target-gene.sh'] + # # network_mode: host + # # stdin_open: true + # # tty: true + # restart: no + # volumes: + # - qiita-data:/qiita_data + # - ./references/qiita_server_certificates:/qiita_server_certificates + # environment: + # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + # networks: + # - qiita-net + + # qtp-visualization: + # image: local-qtp-visualization:latest + # command: ['./start_qtp-visualization.sh'] + # # network_mode: host + # # stdin_open: true + # # tty: true + # restart: no + # volumes: + # - qiita-data:/qiita_data + # - ./references/qiita_server_certificates:/qiita_server_certificates + # environment: + # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + # networks: + # - qiita-net + + # qtp-diversity: + # image: local-qtp-diversity:latest + # command: ['./start_qtp-diversity.sh'] + # # network_mode: host + # # stdin_open: true + # # tty: true + # restart: no + # volumes: + # - qiita-data:/qiita_data + # - ./references/qiita_server_certificates:/qiita_server_certificates + # environment: + # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + # networks: + # - qiita-net + + qp-deblur: + image: janssenlab/qp-deblur:latest + command: ['./start_qp-deblur.sh'] + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - ./references/qp-deblur:/opt/conda/envs/deblur/share/fragment-insertion/ref + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net + + # qp-qiime2: + # image: local-qp-qiime2:latest + # command: ['./start_qp-qiime2.sh'] + # # network_mode: host + # # stdin_open: true + # # tty: true + # restart: no + # volumes: + # - qiita-data:/qiita_data + # - ./references/qiita_server_certificates:/qiita_server_certificates + # environment: + # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + # - TZ=Europe/Berlin # this is important to avoid a local timezone error! See https://forum.qiime2.org/t/qiime2-timezone-error/17410 + # networks: + # - qiita-net + + # qtp-job-output-folder: + # image: local-qtp-job-output-folder:latest + # command: ['./start_qtp-job-output-folder.sh'] + # # network_mode: host + # # stdin_open: true + # # tty: true + # restart: no + # volumes: + # - qiita-data:/qiita_data + # - ./references/qiita_server_certificates:/qiita_server_certificates + # environment: + # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + # networks: + # - qiita-net + + plugin-collector: + # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers + # to compile all q*.conf files from plugin containers in the server-plugin-configs volume + image: janssenlab/plugin_collector:latest + restart: no + networks: + - qiita-net + volumes: + - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r + - server-plugin-configs:/qiita_plugins + - qiita-data:/qiita_data + depends_on: + qiita-initialize-db: + condition: service_completed_successfully + # qtp-biom: # one of the plugins + # condition: service_started + # qtp-sequencing: + # condition: service_started + # qp-target-gene: + # condition: service_started + # qtp-visualization: + # condition: service_started + # qtp-diversity: + # condition: service_started + qp-deblur: + condition: service_started + # qp-qiime2: + # condition: service_started + # qtp-job-output-folder: + # condition: service_started + environment: + - QIITA_PLUGINS="qp-deblur:" + command: ['/start_plugin_collector.sh'] + +networks: + qiita-net: + name: qiita-net + +volumes: + postgres-data: + qiita-data: + server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files From 41516db101d3d3a250295cc943324d912fa7894c Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 08:55:25 +0200 Subject: [PATCH 182/287] execute more make targets --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 6c102c1..12c2539 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -46,7 +46,7 @@ jobs: - name: Make tinqiita targets run: | - make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre + make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config - name: Run docker compose uses: hoverkraft-tech/compose-action@v2.0.1 From 03ab34daf3e7c26d64639055ff9fdd86f51b037e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 11:11:27 +0200 Subject: [PATCH 183/287] also push to tag "latest" --- .github/workflows/buildContainer.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 12c2539..af869f7 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -42,7 +42,9 @@ jobs: context: . push: true file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - tags: ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} + tags: | + ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} + ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:latest - name: Make tinqiita targets run: | From 2c56710512a0a862ce2cd961848514cbbdb192f8 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 11:12:47 +0200 Subject: [PATCH 184/287] create latest for all --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index af869f7..380ffa0 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", #, "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", "qtp-diversity", + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", "qtp-diversity", "qiita", "plugin_collector"] runs-on: ubuntu-latest steps: From 6a93de8818a0d1749721ba858f3b2ae2998768d7 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 11:13:09 +0200 Subject: [PATCH 185/287] limit to save compute --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 380ffa0..23a1e8f 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", "qtp-diversity", + plugin: ["qp-deblur", #"qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", "qtp-diversity", "qiita", "plugin_collector"] runs-on: ubuntu-latest steps: From a73543c7be1476792a70c68ed79e3cabcc46ce6f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 11:15:06 +0200 Subject: [PATCH 186/287] all but diversity --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 23a1e8f..11c73b0 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", #"qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", "qtp-diversity", + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", "qiita", "plugin_collector"] runs-on: ubuntu-latest steps: From 040325e235bd85ada70da6883e3834c14a38bb35 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 11:47:33 +0200 Subject: [PATCH 187/287] no compose for the moment --- .github/workflows/buildContainer.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 11c73b0..d698e77 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -50,7 +50,7 @@ jobs: run: | make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config - - name: Run docker compose - uses: hoverkraft-tech/compose-action@v2.0.1 - with: - compose-file: "compose_github.yaml" \ No newline at end of file + # - name: Run docker compose + # uses: hoverkraft-tech/compose-action@v2.0.1 + # with: + # compose-file: "compose_github.yaml" \ No newline at end of file From 41d7f7065898b5b53390f5a31caea5ffd7f693cd Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 12:00:34 +0200 Subject: [PATCH 188/287] restructure into build, test, push --- .github/workflows/buildContainer.yaml | 43 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index d698e77..ab27076 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", + plugin: ["qp-deblur", #"qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", "qiita", "plugin_collector"] runs-on: ubuntu-latest steps: @@ -36,21 +36,44 @@ jobs: mkdir -p qiita_server_certificates/ echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt - - name: Build and push Docker image + + - name: Build Image (but don not push yet) uses: docker/build-push-action@v6 with: context: . - push: true + push: false + load: true file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - tags: | - ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} - ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:latest + tags: tinqiita/${{ matrix.plugin }}:testcandidate - name: Make tinqiita targets run: | make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config - # - name: Run docker compose - # uses: hoverkraft-tech/compose-action@v2.0.1 - # with: - # compose-file: "compose_github.yaml" \ No newline at end of file + - name: Run docker compose + uses: hoverkraft-tech/compose-action@v2.0.1 + with: + compose-file: "compose_github.yaml" + + - name: Push production image (only if tests passed) + if: success() + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: | + ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} + ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:latest + + + + # - name: Run integration tests with docker-compose + # run: | + # docker compose -f docker-compose.test.yml up -d + # # kurze Wartezeit, bis Services bereit sind + # sleep 10 + # # Beispiel: Tests im Container ausführen + # docker exec my_service_container pytest -v + # docker compose -f docker-compose.test.yml down + + From a909e2c93aa91e0767163a78d261a91a1fad37fd Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 12:01:42 +0200 Subject: [PATCH 189/287] only deblur --- .github/workflows/buildContainer.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index ab27076..2a9f4eb 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,8 +9,9 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", #"qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", - "qiita", "plugin_collector"] + plugin: ["qp-deblur" #, #"qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", + # "qiita", "plugin_collector" + ] runs-on: ubuntu-latest steps: - name: Checkout repository From bbb98742af20192f3d508a366f89a74ac63004c1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 12:02:36 +0200 Subject: [PATCH 190/287] only qtp sequencing --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 2a9f4eb..e2c6708 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur" #, #"qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", + plugin: ["qtp-sequencing" # "qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", # "qiita", "plugin_collector" ] runs-on: ubuntu-latest From 59afc2213ce5c9b78e8a682314a5a709372682fb Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 12:18:26 +0200 Subject: [PATCH 191/287] mount log dir to containers --- .github/workflows/buildContainer.yaml | 15 ++++- compose_github.yaml | 80 ++++++++++++++------------- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index e2c6708..1d110a2 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -38,7 +38,7 @@ jobs: echo "fake" > qiita_server_certificates/qiita_server_certificates.pem echo "fake" > qiita_server_certificates/fake_server.crt - - name: Build Image (but don not push yet) + - name: Build Image (but do not push yet) uses: docker/build-push-action@v6 with: context: . @@ -51,10 +51,23 @@ jobs: run: | make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config + - name: adapt compose file to select specific plugin + run: | + sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml + sed -i "s|image: janssenlab/${{ matrix.plugin }}:latest|image: tinqiita/${{ matrix.plugin }}:testcandidate|" compose_github.yaml + - name: Run docker compose uses: hoverkraft-tech/compose-action@v2.0.1 with: compose-file: "compose_github.yaml" + services: | + qiita-db + qiita-initialize-db + qiita + qiita-worker + redis + nginx + ${{ matrix.plugin }} - name: Push production image (only if tests passed) if: success() diff --git a/compose_github.yaml b/compose_github.yaml index 54756e1..fa63e80 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -35,6 +35,7 @@ services: - server-plugin-configs:/qiita_plugins - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r + - qiita-logs:/logs networks: - qiita-net @@ -63,7 +64,7 @@ services: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG volumes: - qiita-data:/qiita_data - - ./logs:/logs + - qiita-logs:/logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins @@ -101,7 +102,7 @@ services: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG volumes: - qiita-data:/qiita_data - - ./logs:/logs + - qiita-logs:/logs - ./Images/qiita/config_qiita_oidc.cfg:/qiita_configurations/qiita_server.cfg:r - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins @@ -119,7 +120,7 @@ services: redis-server --port 6379" volumes: - qiita-data:/qiita - - ./logs:/logs + - qiita-logs:/logs networks: - qiita-net @@ -136,14 +137,14 @@ services: - qiita volumes: - qiita-data:/qiita_data - - ./logs:/logs + - qiita-logs:/logs - ./Images/nginx/nginx_qiita.conf:/qiita_configuration/nginx_qiita.conf - ./references/qiita_server_certificates:/qiita_certificates networks: - qiita-net # qtp-biom: - # image: local-qtp-biom:latest + # image: janssenlab/qtp-biom:latest # command: ['./start_qtp-biom.sh'] # # network_mode: host # # stdin_open: true @@ -158,9 +159,24 @@ services: # networks: # - qiita-net - # qtp-sequencing: - # image: local-qtp-sequencing:latest - # command: ['./start_qtp-sequencing.sh'] + qtp-sequencing: + image: janssenlab/qtp-sequencing:latest + command: ['./start_qtp-sequencing.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net + + # qp-target-gene: + # image: janssenlab/qp-target-gene:latest + # command: ['./start_qp-target-gene.sh'] # # network_mode: host # # stdin_open: true # # tty: true @@ -173,9 +189,9 @@ services: # networks: # - qiita-net - # qp-target-gene: - # image: local-qp-target-gene:latest - # command: ['./start_qp-target-gene.sh'] + # qtp-visualization: + # image: janssenlab/qtp-visualization:latest + # command: ['./start_qtp-visualization.sh'] # # network_mode: host # # stdin_open: true # # tty: true @@ -188,9 +204,9 @@ services: # networks: # - qiita-net - # qtp-visualization: - # image: local-qtp-visualization:latest - # command: ['./start_qtp-visualization.sh'] + # qtp-diversity: + # image: janssenlab/qtp-diversity:latest + # command: ['./start_qtp-diversity.sh'] # # network_mode: host # # stdin_open: true # # tty: true @@ -203,36 +219,21 @@ services: # networks: # - qiita-net - # qtp-diversity: - # image: local-qtp-diversity:latest - # command: ['./start_qtp-diversity.sh'] - # # network_mode: host - # # stdin_open: true - # # tty: true + # qp-deblur: + # image: janssenlab/qp-deblur:latest + # command: ['./start_qp-deblur.sh'] # restart: no # volumes: # - qiita-data:/qiita_data # - ./references/qiita_server_certificates:/qiita_server_certificates + # - ./references/qp-deblur:/opt/conda/envs/deblur/share/fragment-insertion/ref # environment: # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG # networks: # - qiita-net - qp-deblur: - image: janssenlab/qp-deblur:latest - command: ['./start_qp-deblur.sh'] - restart: no - volumes: - - qiita-data:/qiita_data - - ./references/qiita_server_certificates:/qiita_server_certificates - - ./references/qp-deblur:/opt/conda/envs/deblur/share/fragment-insertion/ref - environment: - - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - networks: - - qiita-net - # qp-qiime2: - # image: local-qp-qiime2:latest + # image: janssenlab/qp-qiime2:latest # command: ['./start_qp-qiime2.sh'] # # network_mode: host # # stdin_open: true @@ -248,7 +249,7 @@ services: # - qiita-net # qtp-job-output-folder: - # image: local-qtp-job-output-folder:latest + # image: janssenlab/qtp-job-output-folder:latest # command: ['./start_qtp-job-output-folder.sh'] # # network_mode: host # # stdin_open: true @@ -276,6 +277,8 @@ services: depends_on: qiita-initialize-db: condition: service_completed_successfully + MATRIXPLUGIN: + condition: service_started # qtp-biom: # one of the plugins # condition: service_started # qtp-sequencing: @@ -286,14 +289,14 @@ services: # condition: service_started # qtp-diversity: # condition: service_started - qp-deblur: - condition: service_started + # qp-deblur: + # condition: service_started # qp-qiime2: # condition: service_started # qtp-job-output-folder: # condition: service_started environment: - - QIITA_PLUGINS="qp-deblur:" + - QIITA_PLUGINS="MATRIXPLUGIN:" command: ['/start_plugin_collector.sh'] networks: @@ -304,3 +307,4 @@ volumes: postgres-data: qiita-data: server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files + qiita-logs: \ No newline at end of file From 3fea4140ea60d15ab2485e06d2297122a3893e5a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 14:31:57 +0200 Subject: [PATCH 192/287] execute test --- .github/workflows/buildContainer.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 1d110a2..13db6d0 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -68,6 +68,9 @@ jobs: redis nginx ${{ matrix.plugin }} + - name: Execute tests in the running services + run: | + docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find / -name "testing.py" | grep qiita_client`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" - name: Push production image (only if tests passed) if: success() @@ -75,6 +78,7 @@ jobs: with: context: . push: true + file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: | ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:latest From b332144620b3597e47f136099d8d26266f2cc9a1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 14:53:35 +0200 Subject: [PATCH 193/287] change localhost on other places as well --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 13db6d0..b192984 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -70,7 +70,7 @@ jobs: ${{ matrix.plugin }} - name: Execute tests in the running services run: | - docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find / -name "testing.py" | grep qiita_client`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" + docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name "testing.py" | grep qiita_client`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; for f in `find ${{ matrix.plugin }}/*/tests/ -name "test_*.py`; do sed -i \"s|https://localhost:21174|https://tinqiita-nginx-1:8383|\" $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" - name: Push production image (only if tests passed) if: success() From 2d66191140403bb6e77112f858f53c30689979b4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 15:01:10 +0200 Subject: [PATCH 194/287] fix quotes --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index b192984..d78ff2d 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -70,7 +70,7 @@ jobs: ${{ matrix.plugin }} - name: Execute tests in the running services run: | - docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name "testing.py" | grep qiita_client`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; for f in `find ${{ matrix.plugin }}/*/tests/ -name "test_*.py`; do sed -i \"s|https://localhost:21174|https://tinqiita-nginx-1:8383|\" $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" + docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name testing.py`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; for f in `find ${{ matrix.plugin }}/*/tests/ -name 'test_*.py'`; do sed -i \"s|https://localhost:21174|https://tinqiita-nginx-1:8383|\" $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" - name: Push production image (only if tests passed) if: success() From cdd6a67ccd70f7880a4e5469739c4a7472f0eba6 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 15:26:04 +0200 Subject: [PATCH 195/287] / is important --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index d78ff2d..254dc35 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -70,7 +70,7 @@ jobs: ${{ matrix.plugin }} - name: Execute tests in the running services run: | - docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name testing.py`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; for f in `find ${{ matrix.plugin }}/*/tests/ -name 'test_*.py'`; do sed -i \"s|https://localhost:21174|https://tinqiita-nginx-1:8383|\" $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" + docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name \"testing.py\"`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; for f in `find /${{ matrix.plugin }}/*/tests/ -name 'test_*.py'`; do sed -i \"s|https://localhost:21174|https://tinqiita-nginx-1:8383|\" $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" - name: Push production image (only if tests passed) if: success() From e15f23cd3c272dd016831cda9e0a38629c3fbfcb Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 17:42:34 +0200 Subject: [PATCH 196/287] extend make to copy test --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8f9a537..d1dae45 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh Images/qtp-sequencing/requirements.txt +.built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh Images/qtp-sequencing/test_qtp-sequencing.sh Images/qtp-sequencing/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` @@ -59,7 +59,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qtp-diversity: Images/qtp-diversity/qtp-diversity.dockerfile Images/qtp-diversity/start_qtp-diversity.sh +.built_image_qtp-diversity: Images/qtp-diversity/qtp-diversity.dockerfile Images/qtp-diversity/start_qtp-diversity.sh Images/qtp-diversity/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` @@ -105,7 +105,7 @@ $(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre: cd Images/qiita && $(PODMAN_BIN) build . -f `basename $<` $(PODMAN_FLAGS) -t local-qiita touch .built_image_qiita -.built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/startup_plugin_collector.sh +.built_image_plugin_collector: Images/plugin_collector/plugin_collector.dockerfile Images/plugin_collector/fix_test_db.py Images/plugin_collector/collect_configs.py Images/plugin_collector/start_plugin_collector.sh tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-plugin_collector From 92470fa3570a544bbb17f418eb481b52eb2489db Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 17:42:59 +0200 Subject: [PATCH 197/287] add new script --- Images/qtp-sequencing/test_qtp-sequencing.sh | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Images/qtp-sequencing/test_qtp-sequencing.sh diff --git a/Images/qtp-sequencing/test_qtp-sequencing.sh b/Images/qtp-sequencing/test_qtp-sequencing.sh new file mode 100644 index 0000000..7f98b5a --- /dev/null +++ b/Images/qtp-sequencing/test_qtp-sequencing.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +echo "plugin to be tested is: '$PLUGIN':wq" + +# install dependencies +apt-get update +apt-get install git +pip install pytest + +# clone plugin repository +git clone https://github.com/qiita-spots/${PLUGIN} + +# fix qiita base url in client +for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name "testing.py"`; do + sed -i 's|URL = "https://localhost:8383"|URL = "https://tinqiita-nginx-1:8383"|' $f; +done + +# fix qiita base url in plugin tests +for f in `find ${PLUGIN}/*/tests/ -name 'test_*.py'`; do + sed -i 's|https://localhost:21174|https://tinqiita-nginx-1:8383|' $f; +done + +# better save than sorry +export QIITA_PORT=8383; + +# change into plugin source directory +cd ${PLUGIN} + +# execute actual tests +pytest From 93a15c3b232410c5706d47e9478a132e5de764e3 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 17:43:11 +0200 Subject: [PATCH 198/287] add missing file --- Images/qtp-diversity/requirements.txt | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Images/qtp-diversity/requirements.txt diff --git a/Images/qtp-diversity/requirements.txt b/Images/qtp-diversity/requirements.txt new file mode 100644 index 0000000..7e0eb3a --- /dev/null +++ b/Images/qtp-diversity/requirements.txt @@ -0,0 +1,34 @@ +-e /q2-metadata +-e /q2-mystery-stew +-e /q2-types +-e /q2-taxa +-e /q2-diversity +-e /q2-diversity-lib +-e /q2cli +-e /q2templates +-e /qiime2 + +tornado +pip-system-certs +pyyaml +decorator +tzlocal +bibtexparser +psutil +flufl.lock +parsl +appdirs +tomlkit +scikit-bio +rnanorm +seaborn +jinja2 +ijson +pyhmmer +frictionless +numpy +-e /unifrac + +-e /qtp-diversity +-e /qiita-files +-e /qiita_client \ No newline at end of file From 5a97f8eb64af8189094862963305f3be885c67a2 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 17:43:28 +0200 Subject: [PATCH 199/287] outsource commands to extra script --- .github/workflows/buildContainer.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 254dc35..3b31752 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -31,7 +31,7 @@ jobs: run: | VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/${{ matrix.plugin }}/test_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . mkdir -p qiita_server_certificates/ @@ -70,7 +70,7 @@ jobs: ${{ matrix.plugin }} - name: Execute tests in the running services run: | - docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "apt-get update; apt-get install git; pip install pytest; git clone https://github.com/qiita-spots/${{ matrix.plugin }}; for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name \"testing.py\"`; do sed -i 's|URL = \"https://localhost:8383\"|URL = \"https://tinqiita-nginx-1:8383\"' $f; done; for f in `find /${{ matrix.plugin }}/*/tests/ -name 'test_*.py'`; do sed -i \"s|https://localhost:21174|https://tinqiita-nginx-1:8383|\" $f; done; export QIITA_PORT=8383; cd ${{ matrix.plugin }}; pytest" + docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "PLUGIN=${{ matrix.plugin }}; bash /test_${{ matrix.plugin }}.sh" - name: Push production image (only if tests passed) if: success() From abb9d36c0d056451fc230984ba1bf0463505a857 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 17:53:25 +0200 Subject: [PATCH 200/287] only service name --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 3b31752..6d78454 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -70,7 +70,7 @@ jobs: ${{ matrix.plugin }} - name: Execute tests in the running services run: | - docker compose exec tinqiita-${{ matrix.plugin }}-1 /bin/bash -c "PLUGIN=${{ matrix.plugin }}; bash /test_${{ matrix.plugin }}.sh" + docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }}; bash /test_${{ matrix.plugin }}.sh" - name: Push production image (only if tests passed) if: success() From ae047a7301a49834e3e2f2a4b6607f476cda763f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 20:35:08 +0200 Subject: [PATCH 201/287] copy test script --- Images/qtp-sequencing/qtp-sequencing.dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index 23acc0e..35b5182 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -94,4 +94,7 @@ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN configure_qtp_sequencing --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-sequencing/" /unshared_plugins/*.conf +# for testing +COPY test_qtp-sequencing.sh /test_qtp-sequencing.sh + CMD ["./start_qtp-sequencing.sh"] \ No newline at end of file From c704f3fb931f927e948d008ec7b1b215a216ba42 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 2 Sep 2025 20:43:49 +0200 Subject: [PATCH 202/287] pass plugin variable --- .github/workflows/buildContainer.yaml | 2 +- Images/qtp-sequencing/test_qtp-sequencing.sh | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 6d78454..1337f80 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -70,7 +70,7 @@ jobs: ${{ matrix.plugin }} - name: Execute tests in the running services run: | - docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }}; bash /test_${{ matrix.plugin }}.sh" + docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_${{ matrix.plugin }}.sh" - name: Push production image (only if tests passed) if: success() diff --git a/Images/qtp-sequencing/test_qtp-sequencing.sh b/Images/qtp-sequencing/test_qtp-sequencing.sh index 7f98b5a..bdff3b8 100644 --- a/Images/qtp-sequencing/test_qtp-sequencing.sh +++ b/Images/qtp-sequencing/test_qtp-sequencing.sh @@ -4,7 +4,7 @@ echo "plugin to be tested is: '$PLUGIN':wq" # install dependencies apt-get update -apt-get install git +apt-get -y --fix-missing install git pip install pytest # clone plugin repository @@ -16,15 +16,12 @@ for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name "testing done # fix qiita base url in plugin tests -for f in `find ${PLUGIN}/*/tests/ -name 'test_*.py'`; do +for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do sed -i 's|https://localhost:21174|https://tinqiita-nginx-1:8383|' $f; done # better save than sorry export QIITA_PORT=8383; -# change into plugin source directory -cd ${PLUGIN} - -# execute actual tests -pytest +# change into plugin source directory and execute actual tests +cd ${PLUGIN} && pytest From 26eeda8e08bb036a73228bce7417f944ed0a289e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 3 Sep 2025 08:23:34 +0200 Subject: [PATCH 203/287] compose up with qiita-worker only as this seems to be the "axiom" --- .github/workflows/buildContainer.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 1337f80..b562ff4 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -61,13 +61,7 @@ jobs: with: compose-file: "compose_github.yaml" services: | - qiita-db - qiita-initialize-db - qiita qiita-worker - redis - nginx - ${{ matrix.plugin }} - name: Execute tests in the running services run: | docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_${{ matrix.plugin }}.sh" From 7735a3bb12694fd3d419db72dc8d9d157502b17e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 3 Sep 2025 14:24:19 +0200 Subject: [PATCH 204/287] install wget to enable docker compose health checks --- Images/qtp-sequencing/qtp-sequencing.dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index 35b5182..c799b54 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -94,6 +94,15 @@ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN configure_qtp_sequencing --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-sequencing/" /unshared_plugins/*.conf +# for docker compose health check +RUN mkdir -p /usr/share/man/man1 && \ + echo "deb [trusted=yes] http://archive.debian.org/debian buster main" > /etc/apt/sources.list && \ + echo "deb [trusted=yes] http://archive.debian.org/debian-security buster/updates main" >> /etc/apt/sources.list && \ + echo "deb [trusted=yes] http://archive.debian.org/debian buster-updates main" >> /etc/apt/sources.list && \ + apt-get update && \ + apt-get install -y --no-install-recommends wget && \ + rm -rf /var/lib/apt/lists/* + # for testing COPY test_qtp-sequencing.sh /test_qtp-sequencing.sh From d97a088c0e9b5851fba3f9c9a70dcc02e59d8854 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 3 Sep 2025 14:24:44 +0200 Subject: [PATCH 205/287] add health checks --- compose_github.yaml | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/compose_github.yaml b/compose_github.yaml index fa63e80..6efaea6 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -19,6 +19,12 @@ services: - qiita-net ports: - "15432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 20s qiita-initialize-db: image: janssenlab/qiita:latest @@ -115,14 +121,23 @@ services: redis: image: redis:latest restart: no + environment: + - PORTSTATS=7777 + - PORTREDBIOM=6379 command: > - sh -c "redis-server --port 7777 && - redis-server --port 6379" + sh -c "redis-server --port $$PORTSTATS && + redis-server --port $$PORTREDBIOM" volumes: - qiita-data:/qiita - qiita-logs:/logs networks: - qiita-net + healthcheck: + test: ["CMD-SHELL", "redis-cli -p $$PORTSTATS ping"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 20s nginx: image: janssenlab/nginx:latest @@ -142,6 +157,15 @@ services: - ./references/qiita_server_certificates:/qiita_certificates networks: - qiita-net + healthcheck: + # looks wired as wget is the busybox version and lacks certificates + # we thus just test if anything answers on the port, otherwise nginx + # returns a "Connection refused" + test: ["CMD-SHELL", "wget https://tinqiita-nginx-1:8383 2>&1 | grep refused -c || true"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s # qtp-biom: # image: janssenlab/qtp-biom:latest @@ -173,6 +197,12 @@ services: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: - qiita-net + healthcheck: + test: ["CMD-SHELL", "wget http://localhost:5000/config -O /dev/null || exit 1"] + interval: 10s + timeout: 5s + retries: 2 + start_period: 3s # qp-target-gene: # image: janssenlab/qp-target-gene:latest @@ -278,7 +308,7 @@ services: qiita-initialize-db: condition: service_completed_successfully MATRIXPLUGIN: - condition: service_started + condition: service_healthy # qtp-biom: # one of the plugins # condition: service_started # qtp-sequencing: From e3827214b257a1a9c3b62fa22abe6eea5a0ae544 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 3 Sep 2025 14:48:15 +0200 Subject: [PATCH 206/287] redefine axiom --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index b562ff4..641a7e2 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -61,7 +61,7 @@ jobs: with: compose-file: "compose_github.yaml" services: | - qiita-worker + nginx - name: Execute tests in the running services run: | docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_${{ matrix.plugin }}.sh" From f3120b44243978ca6437f1060a60f4591072d6cc Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 3 Sep 2025 16:36:59 +0200 Subject: [PATCH 207/287] used blocking tornado calls :-/ --- Images/qp-deblur/trigger_noconda.py | 35 +++++++++++++++++---------- Images/qtp-biom/trigger.py | 37 ++++++++++++++++++----------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/Images/qp-deblur/trigger_noconda.py b/Images/qp-deblur/trigger_noconda.py index 00890aa..cd22b69 100644 --- a/Images/qp-deblur/trigger_noconda.py +++ b/Images/qp-deblur/trigger_noconda.py @@ -6,11 +6,12 @@ import sys import traceback import os +import asyncio plugin_start_script = None class RunCommandHandler(tornado.web.RequestHandler): - def post(self): + async def post(self): try: # JSON-Request-Daten lesen data = json.loads(self.request.body.decode("utf-8")) @@ -27,13 +28,21 @@ def post(self): # Systembefehl ausfuehren cmd = '%s %s %s %s' % (plugin_start_script, qiita_worker_url, job_id, output_dir) - result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) + # Asynchronen Subprozess starten + proc = await asyncio.create_subprocess_exec( + cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + executable='/bin/bash' + ) + stdout, stderr = await proc.communicate() + #result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Antwort zurueckgeben self.write({ - "stdout": result.stdout, - "stderr": result.stderr, - "returncode": result.returncode, + "stdout": stdout.decode(), + "stderr": stderr.decode(), + "returncode": proc.returncode, "cmd": cmd, }) @@ -46,14 +55,14 @@ def post(self): self.write({"error": str(e)}) class RunConfigHandler(tornado.web.RequestHandler): - def get(self): - try: - for fp_config in glob('/unshared_plugins/*.conf'): - with open(fp_config, 'r') as f: - self.write('\n'.join(f.readlines()) + '\n') - except Exception as e: - self.set_status(500) - self.write({"error": str(e)}) + async def get(self): + try: + for fp_config in glob('/unshared_plugins/*.conf'): + with open(fp_config, 'r') as f: + self.write('\n'.join(f.readlines()) + '\n') + except Exception as e: + self.set_status(500) + self.write({"error": str(e)}) def make_app(): return tornado.web.Application([ diff --git a/Images/qtp-biom/trigger.py b/Images/qtp-biom/trigger.py index aec0f47..c644a60 100644 --- a/Images/qtp-biom/trigger.py +++ b/Images/qtp-biom/trigger.py @@ -5,13 +5,14 @@ from glob import glob import sys import traceback +import asyncio conda_env_name = None plugin_start_script = None plugin_src_dir = None class RunCommandHandler(tornado.web.RequestHandler): - def post(self): + async def post(self): try: # JSON-Request-Daten lesen data = json.loads(self.request.body.decode("utf-8")) @@ -27,14 +28,22 @@ def post(self): return # Systembefehl ausfuehren - cmd = 'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s; %s/scripts/%s %s %s %s' % (conda_env_name, plugin_src_dir, plugin_start_script, qiita_worker_url, job_id, output_dir) - result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cmd = '%s %s %s %s' % (plugin_start_script, qiita_worker_url, job_id, output_dir) + # Asynchronen Subprozess starten + proc = await asyncio.create_subprocess_exec( + cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + executable='/bin/bash' + ) + stdout, stderr = await proc.communicate() + #result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Antwort zurueckgeben self.write({ - "stdout": result.stdout, - "stderr": result.stderr, - "returncode": result.returncode, + "stdout": stdout.decode(), + "stderr": stderr.decode(), + "returncode": proc.returncode, "cmd": cmd, }) @@ -50,14 +59,14 @@ def post(self): self.write({"error": str(e)}) class RunConfigHandler(tornado.web.RequestHandler): - def get(self): - try: - for fp_config in glob('/unshared_plugins/*.conf'): - with open(fp_config, 'r') as f: - self.write('\n'.join(f.readlines()) + '\n') - except Exception as e: - self.set_status(500) - self.write({"error": str(e)}) + async def get(self): + try: + for fp_config in glob('/unshared_plugins/*.conf'): + with open(fp_config, 'r') as f: + self.write('\n'.join(f.readlines()) + '\n') + except Exception as e: + self.set_status(500) + self.write({"error": str(e)}) def make_app(): return tornado.web.Application([ From 4b7fc1c20c64e8d4c5ec56d04729ed7ae6c8c963 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Wed, 3 Sep 2025 16:46:28 +0200 Subject: [PATCH 208/287] wait 1min for qiita to get initialized prior to tests --- .github/workflows/buildContainer.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 641a7e2..a8101e0 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -62,8 +62,9 @@ jobs: compose-file: "compose_github.yaml" services: | nginx - - name: Execute tests in the running services + - name: Execute tests in the running services (wait till qiita plugins are registered) run: | + sleep 60 docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_${{ matrix.plugin }}.sh" - name: Push production image (only if tests passed) From 1324b39264304206c71bcb1e8b85784c6fd1ce56 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 4 Sep 2025 16:13:26 +0200 Subject: [PATCH 209/287] share /tmp between plugin and main --- compose_github.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compose_github.yaml b/compose_github.yaml index 6efaea6..4759a23 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -75,6 +75,7 @@ services: - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins - ./references/qiita_server_certificates:/qiita_certificates + - test_tmp_dir:/tmp networks: - qiita-net ports: @@ -113,6 +114,7 @@ services: - ./Images/qiita/config_portal.cfg:/qiita_configurations/config_portal.cfg:r - server-plugin-configs:/qiita_plugins - ./references/qiita_server_certificates:/qiita_certificates + - test_tmp_dir:/tmp networks: - qiita-net deploy: @@ -193,6 +195,7 @@ services: volumes: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -337,4 +340,5 @@ volumes: postgres-data: qiita-data: server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files - qiita-logs: \ No newline at end of file + qiita-logs: + test_tmp_dir: # many of plugin tests are written under the assumption that they are executed on same machine as qiita main and thus share /tmp - which is not the case in our docker compose scenario! From fb3da4cd8a10ed13cd77dba4a2560601970b4bab Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 4 Sep 2025 16:40:02 +0200 Subject: [PATCH 210/287] improved dependencies --- compose_github.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compose_github.yaml b/compose_github.yaml index 4759a23..facaac4 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -59,7 +59,8 @@ services: # - 127.0.0.1:8383:8383 #damit bur ich dran komme restart: no depends_on: - - qiita-worker + qiita-worker: + condition: service_started env_file: - './environments/qiita.env' environment: @@ -96,7 +97,8 @@ services: restart: no depends_on: redis: - condition: service_started + condition: service_healthy + restart: true plugin-collector: condition: service_completed_successfully env_file: From 3f61b0618145e662c77e7afddea2f1acbe4de70f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 5 Sep 2025 15:18:45 +0200 Subject: [PATCH 211/287] as I am using a set of commands I need "shell" not "exec" --- Images/qp-deblur/trigger_noconda.py | 5 ++++- Images/qtp-biom/trigger.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Images/qp-deblur/trigger_noconda.py b/Images/qp-deblur/trigger_noconda.py index cd22b69..0ba4c90 100644 --- a/Images/qp-deblur/trigger_noconda.py +++ b/Images/qp-deblur/trigger_noconda.py @@ -29,7 +29,7 @@ async def post(self): # Systembefehl ausfuehren cmd = '%s %s %s %s' % (plugin_start_script, qiita_worker_url, job_id, output_dir) # Asynchronen Subprozess starten - proc = await asyncio.create_subprocess_exec( + proc = await asyncio.create_subprocess_shell( cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, @@ -38,6 +38,9 @@ async def post(self): stdout, stderr = await proc.communicate() #result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if proc.returncode != 0: + self.set_status(500) + # Antwort zurueckgeben self.write({ "stdout": stdout.decode(), diff --git a/Images/qtp-biom/trigger.py b/Images/qtp-biom/trigger.py index c644a60..c017717 100644 --- a/Images/qtp-biom/trigger.py +++ b/Images/qtp-biom/trigger.py @@ -30,7 +30,7 @@ async def post(self): # Systembefehl ausfuehren cmd = '%s %s %s %s' % (plugin_start_script, qiita_worker_url, job_id, output_dir) # Asynchronen Subprozess starten - proc = await asyncio.create_subprocess_exec( + proc = await asyncio.create_subprocess_shell( cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, @@ -39,6 +39,9 @@ async def post(self): stdout, stderr = await proc.communicate() #result = subprocess.run(cmd, shell=True, universal_newlines=True, executable='/bin/bash', stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if proc.returncode != 0: + self.set_status(500) + # Antwort zurueckgeben self.write({ "stdout": stdout.decode(), From 7ee6227cbefb4aba4c022c30d8ae84a81f906a51 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 5 Sep 2025 15:46:03 +0200 Subject: [PATCH 212/287] also set certificates correctly --- Images/qtp-sequencing/test_qtp-sequencing.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Images/qtp-sequencing/test_qtp-sequencing.sh b/Images/qtp-sequencing/test_qtp-sequencing.sh index bdff3b8..ec95eac 100644 --- a/Images/qtp-sequencing/test_qtp-sequencing.sh +++ b/Images/qtp-sequencing/test_qtp-sequencing.sh @@ -21,7 +21,8 @@ for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do done # better save than sorry -export QIITA_PORT=8383; +export QIITA_PORT=8383 +export QIITA_ROOTCA_CERT=$SSL_CERT_FILE # change into plugin source directory and execute actual tests cd ${PLUGIN} && pytest From 7abee11019a2ce2909770912c525b7f9d7c0b06b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 11:42:58 +0200 Subject: [PATCH 213/287] only communicate with Master --- Images/qtp-sequencing/test_qtp-sequencing.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Images/qtp-sequencing/test_qtp-sequencing.sh b/Images/qtp-sequencing/test_qtp-sequencing.sh index ec95eac..6390714 100644 --- a/Images/qtp-sequencing/test_qtp-sequencing.sh +++ b/Images/qtp-sequencing/test_qtp-sequencing.sh @@ -10,18 +10,22 @@ pip install pytest # clone plugin repository git clone https://github.com/qiita-spots/${PLUGIN} +# NOTE: client api reset only works when communicating with Qitta Master, +# thus, you need to directly address the port of the master container. Don't +# go through nginx! + # fix qiita base url in client for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name "testing.py"`; do - sed -i 's|URL = "https://localhost:8383"|URL = "https://tinqiita-nginx-1:8383"|' $f; + sed -i 's|URL = "https://localhost:8383"|URL = "https://tinqiita-qiita-1:21174"|' $f; done # fix qiita base url in plugin tests for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do - sed -i 's|https://localhost:21174|https://tinqiita-nginx-1:8383|' $f; + sed -i 's|https://localhost:21174|https://tinqiita-qiita-1:21174|' $f; done # better save than sorry -export QIITA_PORT=8383 +export QIITA_PORT=21174 export QIITA_ROOTCA_CERT=$SSL_CERT_FILE # change into plugin source directory and execute actual tests From 2fa4d98fb1548152dbcb29d8cfecdd1fb83e3248 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 12:08:55 +0200 Subject: [PATCH 214/287] adding the missing quast dependency --- Images/qtp-sequencing/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Images/qtp-sequencing/requirements.txt b/Images/qtp-sequencing/requirements.txt index 1c88c0e..cbcce99 100644 --- a/Images/qtp-sequencing/requirements.txt +++ b/Images/qtp-sequencing/requirements.txt @@ -1,5 +1,6 @@ tornado pip-system-certs +quast -e /qiita_client -e /qiita-files From c26d84e891ffae7fe2cc14ace97debd1ea4f5386 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 12:16:32 +0200 Subject: [PATCH 215/287] remove health checks --- compose_github.yaml | 63 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/compose_github.yaml b/compose_github.yaml index facaac4..db79c26 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -19,12 +19,12 @@ services: - qiita-net ports: - "15432:5432" - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 20s + # healthcheck: + # test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + # interval: 10s + # timeout: 5s + # retries: 5 + # start_period: 20s qiita-initialize-db: image: janssenlab/qiita:latest @@ -59,8 +59,7 @@ services: # - 127.0.0.1:8383:8383 #damit bur ich dran komme restart: no depends_on: - qiita-worker: - condition: service_started + - qiita-worker env_file: - './environments/qiita.env' environment: @@ -97,8 +96,7 @@ services: restart: no depends_on: redis: - condition: service_healthy - restart: true + condition: service_started plugin-collector: condition: service_completed_successfully env_file: @@ -136,12 +134,12 @@ services: - qiita-logs:/logs networks: - qiita-net - healthcheck: - test: ["CMD-SHELL", "redis-cli -p $$PORTSTATS ping"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 20s + # healthcheck: + # test: ["CMD-SHELL", "redis-cli -p $$PORTSTATS ping"] + # interval: 10s + # timeout: 5s + # retries: 5 + # start_period: 20s nginx: image: janssenlab/nginx:latest @@ -161,15 +159,15 @@ services: - ./references/qiita_server_certificates:/qiita_certificates networks: - qiita-net - healthcheck: - # looks wired as wget is the busybox version and lacks certificates - # we thus just test if anything answers on the port, otherwise nginx - # returns a "Connection refused" - test: ["CMD-SHELL", "wget https://tinqiita-nginx-1:8383 2>&1 | grep refused -c || true"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s + # healthcheck: + # # looks wired as wget is the busybox version and lacks certificates + # # we thus just test if anything answers on the port, otherwise nginx + # # returns a "Connection refused" + # test: ["CMD-SHELL", "wget https://tinqiita-nginx-1:8383 2>&1 | grep refused -c || true"] + # interval: 10s + # timeout: 5s + # retries: 5 + # start_period: 10s # qtp-biom: # image: janssenlab/qtp-biom:latest @@ -202,12 +200,12 @@ services: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: - qiita-net - healthcheck: - test: ["CMD-SHELL", "wget http://localhost:5000/config -O /dev/null || exit 1"] - interval: 10s - timeout: 5s - retries: 2 - start_period: 3s + # healthcheck: + # test: ["CMD-SHELL", "wget http://localhost:5000/config -O /dev/null || exit 1"] + # interval: 10s + # timeout: 5s + # retries: 2 + # start_period: 3s # qp-target-gene: # image: janssenlab/qp-target-gene:latest @@ -313,7 +311,7 @@ services: qiita-initialize-db: condition: service_completed_successfully MATRIXPLUGIN: - condition: service_healthy + condition: service_started # qtp-biom: # one of the plugins # condition: service_started # qtp-sequencing: @@ -344,3 +342,4 @@ volumes: server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files qiita-logs: test_tmp_dir: # many of plugin tests are written under the assumption that they are executed on same machine as qiita main and thus share /tmp - which is not the case in our docker compose scenario! + \ No newline at end of file From 27f4bcf79d19e8027fa4ded6df1a5c552606cd40 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 12:16:47 +0200 Subject: [PATCH 216/287] link quast --- Images/qtp-sequencing/qtp-sequencing.dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index c799b54..a3e5425 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -77,6 +77,9 @@ COPY --from=builder /opt/conda/envs/qtp-sequencing/bin/pigz /usr/local/bin/ COPY trigger_noconda.py /trigger.py +# link to quast program +RUN ln -s /usr/local/bin/quast.py /usr/local/bin/quast + # WORKDIR / COPY start_qtp-sequencing.sh . From 981d7213f8db7f6e535a3e9a5218eeac36a2b919 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 12:52:54 +0200 Subject: [PATCH 217/287] a bit of debug information --- Images/plugin_collector/start_plugin_collector.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Images/plugin_collector/start_plugin_collector.sh b/Images/plugin_collector/start_plugin_collector.sh index 8208fd2..f82fd41 100644 --- a/Images/plugin_collector/start_plugin_collector.sh +++ b/Images/plugin_collector/start_plugin_collector.sh @@ -7,3 +7,6 @@ sleep 3 mkdir -p /qiita_data/working_dir/ /qiita_data/uploads/ python3 /collect_configs.py python3 /fix_test_db.py + +echo "plugin conf dir is >$QIITA_PLUGINS< and contains:" +ls -la $QIITA_PLUGINS From 20acbf8246c2dd8cfb14496d0478229934465c19 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 12:53:11 +0200 Subject: [PATCH 218/287] remove vim leftover --- Images/qtp-sequencing/test_qtp-sequencing.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-sequencing/test_qtp-sequencing.sh b/Images/qtp-sequencing/test_qtp-sequencing.sh index 6390714..4426084 100644 --- a/Images/qtp-sequencing/test_qtp-sequencing.sh +++ b/Images/qtp-sequencing/test_qtp-sequencing.sh @@ -1,6 +1,6 @@ #!/bin/bash -echo "plugin to be tested is: '$PLUGIN':wq" +echo "plugin to be tested is: '$PLUGIN'" # install dependencies apt-get update From 7c17552fc87655726548f8e405fd0de016cb1234 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 13:05:53 +0200 Subject: [PATCH 219/287] debug --- .github/workflows/buildContainer.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index a8101e0..5043636 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -64,7 +64,8 @@ jobs: nginx - name: Execute tests in the running services (wait till qiita plugins are registered) run: | - sleep 60 + sleep 5 + docker compose exec qiita /bin/bash -c "cat /logs/*; cat /qiita_plugins/*" docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_${{ matrix.plugin }}.sh" - name: Push production image (only if tests passed) From 14896e6e2efbe3569b6db2029737ee175abe6113 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 13:20:58 +0200 Subject: [PATCH 220/287] let make create real certificates --- .github/workflows/buildContainer.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 5043636..285e68f 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -34,9 +34,6 @@ jobs: cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/${{ matrix.plugin }}/test_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . - mkdir -p qiita_server_certificates/ - echo "fake" > qiita_server_certificates/qiita_server_certificates.pem - echo "fake" > qiita_server_certificates/fake_server.crt - name: Build Image (but do not push yet) uses: docker/build-push-action@v6 From bbbb55f91b8605ce5e6882b1b2e0c5a81f87e15b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 13:21:17 +0200 Subject: [PATCH 221/287] no extra newline --- Images/qp-deblur/trigger_noconda.py | 2 +- Images/qtp-biom/trigger.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Images/qp-deblur/trigger_noconda.py b/Images/qp-deblur/trigger_noconda.py index 0ba4c90..5f62d5c 100644 --- a/Images/qp-deblur/trigger_noconda.py +++ b/Images/qp-deblur/trigger_noconda.py @@ -62,7 +62,7 @@ async def get(self): try: for fp_config in glob('/unshared_plugins/*.conf'): with open(fp_config, 'r') as f: - self.write('\n'.join(f.readlines()) + '\n') + self.write(''.join(f.readlines()) + '\n') except Exception as e: self.set_status(500) self.write({"error": str(e)}) diff --git a/Images/qtp-biom/trigger.py b/Images/qtp-biom/trigger.py index c017717..666be08 100644 --- a/Images/qtp-biom/trigger.py +++ b/Images/qtp-biom/trigger.py @@ -66,7 +66,7 @@ async def get(self): try: for fp_config in glob('/unshared_plugins/*.conf'): with open(fp_config, 'r') as f: - self.write('\n'.join(f.readlines()) + '\n') + self.write(''.join(f.readlines()) + '\n') except Exception as e: self.set_status(500) self.write({"error": str(e)}) From ce805c29a59245a26e4bb5e439a71d5e97d12587 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 13:46:07 +0200 Subject: [PATCH 222/287] make before container build to have certificate files ready --- .github/workflows/buildContainer.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 285e68f..ea46978 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -35,6 +35,10 @@ jobs: cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . + - name: Make tinqiita targets + run: | + make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config + - name: Build Image (but do not push yet) uses: docker/build-push-action@v6 with: @@ -44,10 +48,6 @@ jobs: file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: tinqiita/${{ matrix.plugin }}:testcandidate - - name: Make tinqiita targets - run: | - make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config - - name: adapt compose file to select specific plugin run: | sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml From ad6e77b8397d52791fc617f2a839852a4ccb444d Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 13:50:20 +0200 Subject: [PATCH 223/287] rename cert dir for docker build --- .github/workflows/buildContainer.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index ea46978..46f4c24 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -38,6 +38,7 @@ jobs: - name: Make tinqiita targets run: | make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config + mv ./references/qiita_server_certificates ./qiita_server_certificates - name: Build Image (but do not push yet) uses: docker/build-push-action@v6 From 01af883f2856998866188a78999583ae30625079 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 14:00:11 +0200 Subject: [PATCH 224/287] need two copies --- .github/workflows/buildContainer.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 46f4c24..7363829 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -36,9 +36,10 @@ jobs: cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . - name: Make tinqiita targets + # second copy of "qiita_server_certificates" is necessary to match path for docker build, first copy for mounting into container run: | make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config - mv ./references/qiita_server_certificates ./qiita_server_certificates + cp -r ./references/qiita_server_certificates ./qiita_server_certificates - name: Build Image (but do not push yet) uses: docker/build-push-action@v6 From 83e5abc90ba0951b2bd0b9a5d69d250b12e5139c Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 14:11:09 +0200 Subject: [PATCH 225/287] working version --- Images/qtp-sequencing/qtp-sequencing.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index a3e5425..9ec5796 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -1,4 +1,4 @@ -# VERSION: 2025.08.28 +# VERSION: 2025.09.08 # ========================== # Stage 1: Build wheels (~5.8 GB) From e0b2653746e393edfcf033e8a7bcfbaf65f1d955 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 14:16:57 +0200 Subject: [PATCH 226/287] move files for all plugins into Images/ --- Images/qtp-sequencing/qtp-sequencing.dockerfile | 2 +- .../{qtp-sequencing/test_qtp-sequencing.sh => test_plugin.sh} | 0 Images/{qtp-biom => }/trigger.py | 0 Images/{qp-deblur => }/trigger_noconda.py | 0 Makefile | 4 ++-- 5 files changed, 3 insertions(+), 3 deletions(-) rename Images/{qtp-sequencing/test_qtp-sequencing.sh => test_plugin.sh} (100%) rename Images/{qtp-biom => }/trigger.py (100%) rename Images/{qp-deblur => }/trigger_noconda.py (100%) diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index 9ec5796..b6d976f 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -107,6 +107,6 @@ RUN mkdir -p /usr/share/man/man1 && \ rm -rf /var/lib/apt/lists/* # for testing -COPY test_qtp-sequencing.sh /test_qtp-sequencing.sh +COPY test_plugin.sh /test_plugin.sh CMD ["./start_qtp-sequencing.sh"] \ No newline at end of file diff --git a/Images/qtp-sequencing/test_qtp-sequencing.sh b/Images/test_plugin.sh similarity index 100% rename from Images/qtp-sequencing/test_qtp-sequencing.sh rename to Images/test_plugin.sh diff --git a/Images/qtp-biom/trigger.py b/Images/trigger.py similarity index 100% rename from Images/qtp-biom/trigger.py rename to Images/trigger.py diff --git a/Images/qp-deblur/trigger_noconda.py b/Images/trigger_noconda.py similarity index 100% rename from Images/qp-deblur/trigger_noconda.py rename to Images/trigger_noconda.py diff --git a/Makefile b/Makefile index d1dae45..d85d9da 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ $(DIR_REFERENCES)/qiita_server_certificates: Images/plugin_collector/stefan_csr. # === end: create own certificates === # a general target, executed for each plugin -plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REFERENCES)/qiita_server_certificates +plugin: Images/trigger.py Images/trigger_noconda.py $(DIR_REFERENCES)/qiita_server_certificates Images/test_plugin.sh cp -r $^ $(tmpdir)/ .built_image_qtp-biom: Images/qtp-biom/qtp-biom.dockerfile Images/qtp-biom/start_qtp-biom.sh src/qiita-files/ src/qtp-biom/ Images/qtp-biom/requirements.txt @@ -41,7 +41,7 @@ plugin: Images/qtp-biom/trigger.py Images/qp-deblur/trigger_noconda.py $(DIR_REF $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh Images/qtp-sequencing/test_qtp-sequencing.sh Images/qtp-sequencing/requirements.txt +.built_image_qtp-sequencing: Images/qtp-sequencing/qtp-sequencing.dockerfile Images/qtp-sequencing/start_qtp-sequencing.sh Images/qtp-sequencing/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From fb6e772b6014be0da4861e8c8d7b614f6fd32cc4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 14:19:29 +0200 Subject: [PATCH 227/287] fix file path --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 7363829..b74c76a 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -31,7 +31,7 @@ jobs: run: | VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/${{ matrix.plugin }}/test_${{ matrix.plugin }}.sh Images/qp-deblur/trigger_noconda.py Images/qtp-biom/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/trigger_noconda.py Images/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . From 6fff701eb8550d3d4264c1c9d518fa392a6ff795 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 14:38:37 +0200 Subject: [PATCH 228/287] use new file name --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index b74c76a..cd3e840 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -65,7 +65,7 @@ jobs: run: | sleep 5 docker compose exec qiita /bin/bash -c "cat /logs/*; cat /qiita_plugins/*" - docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_${{ matrix.plugin }}.sh" + docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_plugin.sh" - name: Push production image (only if tests passed) if: success() From 879c46858897fb3cdef927e2c9cdb77fbd37d9f4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 14:52:15 +0200 Subject: [PATCH 229/287] test all other plugins (that are small by now) --- .github/workflows/buildContainer.yaml | 18 +-- .../qp-target-gene/qp-target-gene.dockerfile | 3 + Images/qtp-biom/qtp-biom.dockerfile | 3 + Images/qtp-diversity/qtp-diversity.dockerfile | 131 +++++++++++++++--- .../qtp-visualization.dockerfile | 3 + 5 files changed, 124 insertions(+), 34 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index cd3e840..b45a540 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,8 +9,8 @@ jobs: docker: strategy: matrix: - plugin: ["qtp-sequencing" # "qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "nginx", "qtp-visualization", #"qtp-diversity", - # "qiita", "plugin_collector" + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", + "nginx", "qiita", "plugin_collector" ] runs-on: ubuntu-latest steps: @@ -56,6 +56,7 @@ jobs: sed -i "s|image: janssenlab/${{ matrix.plugin }}:latest|image: tinqiita/${{ matrix.plugin }}:testcandidate|" compose_github.yaml - name: Run docker compose + if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} uses: hoverkraft-tech/compose-action@v2.0.1 with: compose-file: "compose_github.yaml" @@ -77,16 +78,3 @@ jobs: tags: | ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:latest - - - - # - name: Run integration tests with docker-compose - # run: | - # docker compose -f docker-compose.test.yml up -d - # # kurze Wartezeit, bis Services bereit sind - # sleep 10 - # # Beispiel: Tests im Container ausführen - # docker exec my_service_container pytest -v - # docker compose -f docker-compose.test.yml down - - diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index d35bc87..3b998c8 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -118,4 +118,7 @@ RUN sed -i "s|^#\!.*|#\!/usr/bin/python2|" /usr/local/bin/start_target_gene RUN configure_target_gene --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-target-gene/" /unshared_plugins/*.conf +# for testing +COPY test_plugin.sh /test_plugin.sh + CMD ["./start_qp-target-gene.sh"] diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 9c8942a..1346a6c 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -169,6 +169,9 @@ RUN sed -i "s/'display.max_colwidth', -1/'display.max_colwidth', None/" /usr/loc # remove conda command from tigger.py # RUN sed -i "s|source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s;||" /trigger.py && sed -i "s|conda_env_name, ||" /trigger.py +# for testing +COPY test_plugin.sh /test_plugin.sh + CMD ["./start_qtp-biom.sh"] # python -c "import qiime2.plugins.feature_table" \ No newline at end of file diff --git a/Images/qtp-diversity/qtp-diversity.dockerfile b/Images/qtp-diversity/qtp-diversity.dockerfile index 1445123..1cfcee4 100644 --- a/Images/qtp-diversity/qtp-diversity.dockerfile +++ b/Images/qtp-diversity/qtp-diversity.dockerfile @@ -1,6 +1,7 @@ -FROM ubuntu:24.04 +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 +ARG QIIME2RELEASE=2022.11 ENV CONDA_DIR=/opt/conda ENV PATH=${CONDA_DIR}/bin:${PATH} @@ -29,44 +30,136 @@ RUN conda install tornado COPY trigger.py /trigger.py # Download qiime2 yaml -RUN wget -q https://data.qiime2.org/distro/core/qiime2-2022.11-py38-linux-conda.yml +RUN wget -q https://data.qiime2.org/distro/core/qiime2-${QIIME2RELEASE}-py38-linux-conda.yml + +RUN sed -n '/channels/,/dependencies/p' qiime2-${QIIME2RELEASE}-py38-linux-conda.yml > tinyq2.yml && \ + echo " - q2-metadata=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-mystery-stew=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-types=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-diversity=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-diversity-lib=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2cli=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2templates=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - q2-taxa=${QIIME2RELEASE}" >> tinyq2.yml && \ + echo " - typeguard=2.13.3" >> tinyq2.yml && \ +# echo " - unifrac-binaries=1.1.1" >> tinyq2.yml && \ + echo " - qiime2" >> tinyq2.yml # Create conda env -RUN conda env create --name qiime2 -y --file qiime2-2022.11-py38-linux-conda.yml +RUN conda config --set channel_priority strict && conda env create --name qiime2 -y --file tinyq2.yml # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qiime2", "/bin/bash", "-c"] RUN pip install -U pip -RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip -RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +# RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN git clone -b master https://github.com/qiita-spots/qiita_client.git +RUN cd qiita_client && pip install --no-cache-dir . + +# RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone -b master https://github.com/qiita-spots/qiita-files.git +RUN cd /qiita-files && pip install -e . -v + RUN pip install https://github.com/biocore/q2-mislabeled/archive/refs/heads/main.zip RUN git clone https://github.com/qiita-spots/qtp-diversity.git -WORKDIR qtp-diversity +WORKDIR /qtp-diversity +RUN sed -i "s|'qiita-files @ https://github.com/'||" setup.py +RUN sed -i "s|'qiita-spots/qiita-files/archive/master.zip',||" setup.py +RUN sed -i "s|'qiita_client @ https://github.com/qiita-spots/'||" setup.py +RUN sed -i "s|'qiita_client/archive/master.zip'||" setup.py RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg - WORKDIR / +RUN repo=q2-metadata; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-mystery-stew; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-types; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2cli; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2templates; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=qiime2; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-taxa; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-diversity; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo +RUN repo=q2-diversity-lib; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo + +RUN repo=unifrac; mkdir -p /$repo && wget -O- https://github.com/biocore/unifrac/archive/refs/tags/1.1.1.tar.gz | tar -xz --strip-components=1 -C /$repo + +COPY requirements.txt ./requirements.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt + +RUN sed -n '/channels/,/dependencies/p' qiime2-${QIIME2RELEASE}-py38-linux-conda.yml > deps.yml && \ + echo " - umap-learn" >> deps.yml && \ + echo " - unifrac=1.1.1" >> deps.yml && \ + echo " - unifrac-binaries=1.1.1" >> deps.yml && \ + echo " - qiime2" >> deps.yml + +# Create conda env +RUN conda config --set channel_priority strict && conda env create --name dependencies -y --file deps.yml + +# ========================== +# Stage 2: Runtime +# ========================== +FROM python:3.8-slim + +# python package compile in build stage +COPY --from=builder /wheels /wheels + +RUN pip install --no-cache-dir /wheels/* \ + && rm -rf rm -rf `find /usr/local/lib/python3.8/site-packages -type d -name "tests" | grep -v numpy` + COPY start_qtp-diversity.sh . RUN chmod 755 start_qtp-diversity.sh RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ -## Export cert and config filepaths -COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem -ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem -ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem +COPY --from=builder /opt/conda/envs/dependencies/bin/* /opt/conda/bin/ +COPY --from=builder /opt/conda/envs/dependencies/sbin/* /opt/conda/sbin/ +COPY --from=builder /opt/conda/envs/dependencies/lib/* /opt/conda/lib/ +COPY --from=builder /opt/conda/envs/dependencies/x86_64-conda-linux-gnu/* /opt/conda/x86_64-conda-linux-gnu/ +ENV PATH=$PATH:/opt/conda/bin:/opt/conda/sbin +# RUN for d in `echo bin lib sbin x86_64-conda-linux-gnu`; do cp -r /dep_conda/$d/* /usr/local/$d/; done + +RUN ln -s /usr/local/lib/python3.8/site-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 + +# # everything for unifrac +# # COPY --from=builder /opt/conda/envs/qiime2/bin/ssu /usr/local/bin/ssu +# # COPY --from=builder /opt/conda/envs/qiime2/bin/faithpd /usr/local/bin/faithpd +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libssu.so /usr/local/lib/libssu.so +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libopenblasp-r0.3.25.so /usr/local/lib/libopenblasp-r0.3.25.so +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl_cpp.so.100.1.4 /usr/local/lib/libhdf5_hl_cpp.so.100 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libgfortran.so.5.0.0 /usr/local/lib/libgfortran.so.5 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libquadmath.so.0.0.0 /usr/local/lib/libquadmath.so.0 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_cpp.so.103.2.0 /usr/local/lib/libhdf5_cpp.so.103 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl_cpp.so.100.1.4 /usr/local/lib/libhdf5_hl_cpp.so.100 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libcrypto.so.1.1 /usr/local/lib/libcrypto.so.1.1 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libcurl.so.4.8.0 /usr/local/lib/libcurl.so.4 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libnghttp2.so.14.24.1 /usr/local/lib/libnghttp2.so.14 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libssh2.so.1.0.1 /usr/local/lib/libssh2.so.1 +# # COPY --from=builder /opt/conda/envs/qiime2/lib/libssl.so.1.1 /usr/local/lib/libssl.so.1.1 +# # RUN ln -s /usr/local/lib/libopenblasp-r0.3.25.so /usr/local/lib/libcblas.so.3 +# # RUN ln -s /usr/local/lib/libopenblasp-r0.3.25.so /usr/local/lib/liblapacke.so.3 +# # RUN for f in `echo "libssu.so libhdf5_cpp.so.103 liblapacke.so.3 libcblas.so.3 libhdf5_hl_cpp.so.100 libhdf5_hl.so.100 libhdf5.so.103 libcrypto.so.1.1 libcurl.so.4 libgfortran.so.5 libnghttp2.so.14 libssh2.so.1 libssl.so.1.1 libquadmath.so.0"`; do ln -s /usr/local/lib/$f /lib/x86_64-linux-gnu/$f; done + +# # COPY trigger_noconda.py /trigger.py +# # ENV LC_ALL=C.UTF-8 +# # ENV LANG=C.UTF-8 + +# # ## Export cert and config filepaths +# # COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +# # ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +# # ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem + +# # #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt +# # RUN chmod u+x /usr/local/bin/configure_diversity_types /usr/local/bin/start_diversity_types +# # COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +# # RUN configure_diversity_types --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +# # RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-diversity/" /unshared_plugins/*.conf -#RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN chmod u+x /qtp-diversity/scripts/configure_diversity_types /qtp-diversity/scripts/start_diversity_types -COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /qtp-diversity/scripts/configure_diversity_types --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` -RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-diversity/" /unshared_plugins/*.conf +# # CMD ["./start_qtp-diversity.sh"] -CMD ["./start_qtp-diversity.sh"] diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile index ca8e51d..53b1d5b 100644 --- a/Images/qtp-visualization/qtp-visualization.dockerfile +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -113,4 +113,7 @@ ENV CONDA_PREFIX=/usr/local RUN configure_visualization_types --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-visualization/" /unshared_plugins/*.conf +# for testing +COPY test_plugin.sh /test_plugin.sh + CMD ["./start_qtp-visualization.sh"] \ No newline at end of file From d3eda665eac97d5302042e52e366e380094f051a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 14:54:59 +0200 Subject: [PATCH 230/287] also skip this step for non plugins --- .github/workflows/buildContainer.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index b45a540..63bff01 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -63,6 +63,7 @@ jobs: services: | nginx - name: Execute tests in the running services (wait till qiita plugins are registered) + if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} run: | sleep 5 docker compose exec qiita /bin/bash -c "cat /logs/*; cat /qiita_plugins/*" From 7e69c6e6e2e01bb39f650a454172ee95dd5ad115 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 15:01:47 +0200 Subject: [PATCH 231/287] bring back other plugin services --- compose_github.yaml | 202 +++++++++++++++++++++++--------------------- 1 file changed, 104 insertions(+), 98 deletions(-) diff --git a/compose_github.yaml b/compose_github.yaml index db79c26..340df52 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -169,21 +169,21 @@ services: # retries: 5 # start_period: 10s - # qtp-biom: - # image: janssenlab/qtp-biom:latest - # command: ['./start_qtp-biom.sh'] - # # network_mode: host - # # stdin_open: true - # # tty: true - # restart: no - # volumes: - # - qiita-data:/qiita_data - # - ./references/qiita_server_certificates:/qiita_server_certificates - # - ./src/qtp-biom:/qtp-biom:U - # environment: - # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - # networks: - # - qiita-net + qtp-biom: + image: janssenlab/qtp-biom:latest + command: ['./start_qtp-biom.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net qtp-sequencing: image: janssenlab/qtp-sequencing:latest @@ -207,94 +207,100 @@ services: # retries: 2 # start_period: 3s - # qp-target-gene: - # image: janssenlab/qp-target-gene:latest - # command: ['./start_qp-target-gene.sh'] - # # network_mode: host - # # stdin_open: true - # # tty: true - # restart: no - # volumes: - # - qiita-data:/qiita_data - # - ./references/qiita_server_certificates:/qiita_server_certificates - # environment: - # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - # networks: - # - qiita-net + qp-target-gene: + image: janssenlab/qp-target-gene:latest + command: ['./start_qp-target-gene.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net - # qtp-visualization: - # image: janssenlab/qtp-visualization:latest - # command: ['./start_qtp-visualization.sh'] - # # network_mode: host - # # stdin_open: true - # # tty: true - # restart: no - # volumes: - # - qiita-data:/qiita_data - # - ./references/qiita_server_certificates:/qiita_server_certificates - # environment: - # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - # networks: - # - qiita-net + qtp-visualization: + image: janssenlab/qtp-visualization:latest + command: ['./start_qtp-visualization.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net - # qtp-diversity: - # image: janssenlab/qtp-diversity:latest - # command: ['./start_qtp-diversity.sh'] - # # network_mode: host - # # stdin_open: true - # # tty: true - # restart: no - # volumes: - # - qiita-data:/qiita_data - # - ./references/qiita_server_certificates:/qiita_server_certificates - # environment: - # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - # networks: - # - qiita-net + qtp-diversity: + image: janssenlab/qtp-diversity:latest + command: ['./start_qtp-diversity.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net - # qp-deblur: - # image: janssenlab/qp-deblur:latest - # command: ['./start_qp-deblur.sh'] - # restart: no - # volumes: - # - qiita-data:/qiita_data - # - ./references/qiita_server_certificates:/qiita_server_certificates - # - ./references/qp-deblur:/opt/conda/envs/deblur/share/fragment-insertion/ref - # environment: - # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - # networks: - # - qiita-net + qp-deblur: + image: janssenlab/qp-deblur:latest + command: ['./start_qp-deblur.sh'] + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - ./references/qp-deblur:/opt/conda/envs/deblur/share/fragment-insertion/ref + - test_tmp_dir:/tmp + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net - # qp-qiime2: - # image: janssenlab/qp-qiime2:latest - # command: ['./start_qp-qiime2.sh'] - # # network_mode: host - # # stdin_open: true - # # tty: true - # restart: no - # volumes: - # - qiita-data:/qiita_data - # - ./references/qiita_server_certificates:/qiita_server_certificates - # environment: - # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - # - TZ=Europe/Berlin # this is important to avoid a local timezone error! See https://forum.qiime2.org/t/qiime2-timezone-error/17410 - # networks: - # - qiita-net + qp-qiime2: + image: janssenlab/qp-qiime2:latest + command: ['./start_qp-qiime2.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + - TZ=Europe/Berlin # this is important to avoid a local timezone error! See https://forum.qiime2.org/t/qiime2-timezone-error/17410 + networks: + - qiita-net - # qtp-job-output-folder: - # image: janssenlab/qtp-job-output-folder:latest - # command: ['./start_qtp-job-output-folder.sh'] - # # network_mode: host - # # stdin_open: true - # # tty: true - # restart: no - # volumes: - # - qiita-data:/qiita_data - # - ./references/qiita_server_certificates:/qiita_server_certificates - # environment: - # - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - # networks: - # - qiita-net + qtp-job-output-folder: + image: janssenlab/qtp-job-output-folder:latest + command: ['./start_qtp-job-output-folder.sh'] + # network_mode: host + # stdin_open: true + # tty: true + restart: no + volumes: + - qiita-data:/qiita_data + - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp + environment: + - QIITA_CLIENT_DEBUG_LEVEL=DEBUG + networks: + - qiita-net plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers From 4d19472e8e569eadfefa86ca42288bf3013374a1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 15:02:04 +0200 Subject: [PATCH 232/287] add shared tmp volume for local testing --- compose.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compose.yaml b/compose.yaml index d9151ef..55ecbf5 100644 --- a/compose.yaml +++ b/compose.yaml @@ -72,6 +72,7 @@ services: - server-plugin-configs:/qiita_plugins - ./references/qiita_server_certificates:/qiita_certificates # - ./Images/qiita/start_qiita.sh:/qiita/start_qiita.sh + - test_tmp_dir:/tmp networks: - qiita-net ports: @@ -113,6 +114,7 @@ services: - ./references/qiita_server_certificates:/qiita_certificates - ./src/qiita:/qiita:U # - ./Images/qiita/start_qiita_worker.sh:/qiita/start_qiita_worker.sh + - test_tmp_dir:/tmp networks: - qiita-net deploy: @@ -200,6 +202,7 @@ services: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates - ./src/qtp-biom:/qtp-biom:U + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -215,6 +218,7 @@ services: volumes: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -230,6 +234,7 @@ services: volumes: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -245,6 +250,7 @@ services: volumes: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -260,6 +266,7 @@ services: volumes: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -277,6 +284,7 @@ services: - ./references/qiita_server_certificates:/qiita_server_certificates - ./references/qp-deblur:/opt/conda/envs/deblur/share/fragment-insertion/ref #- ./src/qtp-biom:/qtp-biom:U + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -292,6 +300,7 @@ services: volumes: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG - TZ=Europe/Berlin # this is important to avoid a local timezone error! See https://forum.qiime2.org/t/qiime2-timezone-error/17410 @@ -308,6 +317,7 @@ services: volumes: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates + - test_tmp_dir:/tmp environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -359,3 +369,5 @@ volumes: #~ name: keycloak-postgres-data qiita-data: server-plugin-configs: # a shared directory on qiita server side (master and workers) to collect qiita plugin configuration files + test_tmp_dir: # many of plugin tests are written under the assumption that they are executed on same machine as qiita main and thus share /tmp - which is not the case in our docker compose scenario! + \ No newline at end of file From a2aebe929f309e496359978d09f15e23a87dc45e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 15:21:15 +0200 Subject: [PATCH 233/287] info about docker images --- .github/workflows/buildContainer.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 63bff01..6404820 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -50,6 +50,11 @@ jobs: file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: tinqiita/${{ matrix.plugin }}:testcandidate + - name: debug docker + run: | + docker image ls -a + docker ps -a + - name: adapt compose file to select specific plugin run: | sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml From 5f709e4145a01f1057c26b18114919954c9409af Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 15:31:03 +0200 Subject: [PATCH 234/287] for plugins: use locally created images, not dockerhub --- compose_github.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compose_github.yaml b/compose_github.yaml index 340df52..e8e5ce5 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -170,7 +170,7 @@ services: # start_period: 10s qtp-biom: - image: janssenlab/qtp-biom:latest + image: tinqiita/qtp-biom:testcandidate command: ['./start_qtp-biom.sh'] # network_mode: host # stdin_open: true @@ -186,7 +186,7 @@ services: - qiita-net qtp-sequencing: - image: janssenlab/qtp-sequencing:latest + image: tinqiita/qtp-sequencing:testcandidate command: ['./start_qtp-sequencing.sh'] # network_mode: host # stdin_open: true @@ -208,7 +208,7 @@ services: # start_period: 3s qp-target-gene: - image: janssenlab/qp-target-gene:latest + image: tinqiita/qp-target-gene:testcandidate command: ['./start_qp-target-gene.sh'] # network_mode: host # stdin_open: true @@ -224,7 +224,7 @@ services: - qiita-net qtp-visualization: - image: janssenlab/qtp-visualization:latest + image: tinqiita/qtp-visualization:testcandidate command: ['./start_qtp-visualization.sh'] # network_mode: host # stdin_open: true @@ -240,7 +240,7 @@ services: - qiita-net qtp-diversity: - image: janssenlab/qtp-diversity:latest + image: tinqiita/qtp-diversity:testcandidate command: ['./start_qtp-diversity.sh'] # network_mode: host # stdin_open: true @@ -256,7 +256,7 @@ services: - qiita-net qp-deblur: - image: janssenlab/qp-deblur:latest + image: tinqiita/qp-deblur:testcandidate command: ['./start_qp-deblur.sh'] restart: no volumes: @@ -270,7 +270,7 @@ services: - qiita-net qp-qiime2: - image: janssenlab/qp-qiime2:latest + image: tinqiita/qp-qiime2:testcandidate command: ['./start_qp-qiime2.sh'] # network_mode: host # stdin_open: true @@ -287,7 +287,7 @@ services: - qiita-net qtp-job-output-folder: - image: janssenlab/qtp-job-output-folder:latest + image: tinqiita/qtp-job-output-folder:testcandidate command: ['./start_qtp-job-output-folder.sh'] # network_mode: host # stdin_open: true From 97eeed8ac1b83679866cde299c70a8ee307702bc Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 15:53:23 +0200 Subject: [PATCH 235/287] switch to harbor --- .github/workflows/buildContainer.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 6404820..eefa047 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -20,8 +20,9 @@ jobs: - name: Login to DockerHub uses: docker/login-action@v3 with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + registry: harbor.computational.bio.uni-giessen.de + username: ${{ vars.HARBOR_CB_USERNAME }} + password: ${{ secrets.HARBOR_CB_TOKEN }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 From 3b68470faaa71aa6695a1393a0842748eafb5b8f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 15:56:09 +0200 Subject: [PATCH 236/287] fix variable name --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index eefa047..610517e 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -22,7 +22,7 @@ jobs: with: registry: harbor.computational.bio.uni-giessen.de username: ${{ vars.HARBOR_CB_USERNAME }} - password: ${{ secrets.HARBOR_CB_TOKEN }} + password: ${{ secrets.HARBOR_CB_SECRET }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 From 3230d078ccc1c536ae038f19c0fcb48abf33fe5e Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 16:12:46 +0200 Subject: [PATCH 237/287] build non tested projects --- .github/workflows/buildContainer.yaml | 6 +++--- compose_github.yaml | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 610517e..83c177e 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", + plugin: [#"qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", "nginx", "qiita", "plugin_collector" ] runs-on: ubuntu-latest @@ -83,5 +83,5 @@ jobs: push: true file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: | - ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} - ${{ vars.DOCKERHUB_USERNAME }}/${{ matrix.plugin }}:latest + harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} + harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:latest diff --git a/compose_github.yaml b/compose_github.yaml index e8e5ce5..6223412 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -27,7 +27,7 @@ services: # start_period: 20s qiita-initialize-db: - image: janssenlab/qiita:latest + image: harbor.computational.bio.uni-giessen.de/tinqiita/qiita:latest command: ['/start_qiita-initDB.sh'] depends_on: - qiita-db @@ -46,7 +46,7 @@ services: - qiita-net qiita: - image: janssenlab/qiita:latest + image: harbor.computational.bio.uni-giessen.de/tinqiita/qiita:latest build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -82,7 +82,7 @@ services: - "21174:21174" qiita-worker: - image: janssenlab/qiita:latest + image: harbor.computational.bio.uni-giessen.de/tinqiita/qiita:latest build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -142,7 +142,7 @@ services: # start_period: 20s nginx: - image: janssenlab/nginx:latest + image: harbor.computational.bio.uni-giessen.de/tinqiita/nginx:latest build: context: ./Images/nginx dockerfile: Dockerfile @@ -305,7 +305,7 @@ services: plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume - image: janssenlab/plugin_collector:latest + image: harbor.computational.bio.uni-giessen.de/tinqiita/plugin_collector:latest restart: no networks: - qiita-net From eaa6e5f90d1ee2a86fed99534f5913b02b813a29 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 16:25:06 +0200 Subject: [PATCH 238/287] now the plugins --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 83c177e..625d6f0 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: [#"qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", "nginx", "qiita", "plugin_collector" ] runs-on: ubuntu-latest From 3ba51a4d1950da2fbeba3ccdad9f0a66d6792e62 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Mon, 8 Sep 2025 16:37:05 +0200 Subject: [PATCH 239/287] remove debug lines, as they might lead to exit != 0 --- Images/plugin_collector/start_plugin_collector.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/Images/plugin_collector/start_plugin_collector.sh b/Images/plugin_collector/start_plugin_collector.sh index f82fd41..8208fd2 100644 --- a/Images/plugin_collector/start_plugin_collector.sh +++ b/Images/plugin_collector/start_plugin_collector.sh @@ -7,6 +7,3 @@ sleep 3 mkdir -p /qiita_data/working_dir/ /qiita_data/uploads/ python3 /collect_configs.py python3 /fix_test_db.py - -echo "plugin conf dir is >$QIITA_PLUGINS< and contains:" -ls -la $QIITA_PLUGINS From 4d780d6274959e7b87e618cf0949db22ae6cf396 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 08:32:21 +0200 Subject: [PATCH 240/287] lean dependencies for qtp-diversity --- Images/qtp-diversity/qtp-diversity.dockerfile | 131 ++++++++++-------- Images/qtp-diversity/requirements.txt | 2 + Images/qtp-diversity/start_qtp-diversity.sh | 2 +- Images/test_plugin.sh | 8 +- 4 files changed, 82 insertions(+), 61 deletions(-) diff --git a/Images/qtp-diversity/qtp-diversity.dockerfile b/Images/qtp-diversity/qtp-diversity.dockerfile index 1cfcee4..0ce792d 100644 --- a/Images/qtp-diversity/qtp-diversity.dockerfile +++ b/Images/qtp-diversity/qtp-diversity.dockerfile @@ -24,11 +24,6 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ conda init && \ rm -f /tmp/miniforge3.sh -# install tornado based trigger layer in base environment -RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py - # Download qiime2 yaml RUN wget -q https://data.qiime2.org/distro/core/qiime2-${QIIME2RELEASE}-py38-linux-conda.yml @@ -42,7 +37,7 @@ RUN sed -n '/channels/,/dependencies/p' qiime2-${QIIME2RELEASE}-py38-linux-conda echo " - q2templates=${QIIME2RELEASE}" >> tinyq2.yml && \ echo " - q2-taxa=${QIIME2RELEASE}" >> tinyq2.yml && \ echo " - typeguard=2.13.3" >> tinyq2.yml && \ -# echo " - unifrac-binaries=1.1.1" >> tinyq2.yml && \ + echo " - unifrac-binaries=1.1.1" >> tinyq2.yml && \ echo " - qiime2" >> tinyq2.yml # Create conda env @@ -60,7 +55,7 @@ RUN cd qiita_client && pip install --no-cache-dir . RUN git clone -b master https://github.com/qiita-spots/qiita-files.git RUN cd /qiita-files && pip install -e . -v -RUN pip install https://github.com/biocore/q2-mislabeled/archive/refs/heads/main.zip +#RUN pip install https://github.com/biocore/q2-mislabeled/archive/refs/heads/main.zip RUN git clone https://github.com/qiita-spots/qtp-diversity.git WORKDIR /qtp-diversity RUN sed -i "s|'qiita-files @ https://github.com/'||" setup.py @@ -83,19 +78,23 @@ RUN repo=q2-taxa; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/ar RUN repo=q2-diversity; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.1.tar.gz | tar -xz --strip-components=1 -C /$repo RUN repo=q2-diversity-lib; mkdir -p /$repo && wget -O- https://github.com/qiime2/$repo/archive/refs/tags/${QIIME2RELEASE}.0.tar.gz | tar -xz --strip-components=1 -C /$repo +# the below one is huge as it installs sourece tracker as dependencies. I think (smj 2025-09-09) that we "just" need the type definition for the CI tests of qtp-diversity. Thus, patch dependency away +RUN repo=q2-mislabeld; mkdir -p /$repo && wget -O- https://github.com/biocore/q2-mislabeled/archive/refs/tags/2023.2.tar.gz | tar -xz --strip-components=1 -C /$repo && cd /$repo && sed -i "s|'sourcetracker @ https://github.com/'||" setup.py && sed -i "s|'wasade/sourcetracker2/archive/be_sparse.zip'||" setup.py && pip install -e . + RUN repo=unifrac; mkdir -p /$repo && wget -O- https://github.com/biocore/unifrac/archive/refs/tags/1.1.1.tar.gz | tar -xz --strip-components=1 -C /$repo COPY requirements.txt ./requirements.txt RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt -RUN sed -n '/channels/,/dependencies/p' qiime2-${QIIME2RELEASE}-py38-linux-conda.yml > deps.yml && \ - echo " - umap-learn" >> deps.yml && \ - echo " - unifrac=1.1.1" >> deps.yml && \ - echo " - unifrac-binaries=1.1.1" >> deps.yml && \ - echo " - qiime2" >> deps.yml +# RUN sed -n '/channels/,/dependencies/p' qiime2-${QIIME2RELEASE}-py38-linux-conda.yml > deps.yml && \ +# echo " - umap-learn" >> deps.yml && \ +# echo " - unifrac=1.1.1" >> deps.yml && \ +# echo " - unifrac-binaries=1.1.1" >> deps.yml && \ +# echo " - qiime2" >> deps.yml -# Create conda env -RUN conda config --set channel_priority strict && conda env create --name dependencies -y --file deps.yml +# # Create conda env +# RUN conda config --set channel_priority strict && conda env create --name dependencies -y --file deps.yml +RUN cd /opt/conda/envs/qiime2/lib/python3.8/site-packages/q2_diversity/ && tar czvf /q2_diversity_assets.tgz _beta/adonis_assets _beta/beta_rarefaction_assets _beta/mantel_assets _beta/beta_group_significance_assets _alpha/alpha_group_significance_assets _alpha/alpha_correlation_assets _alpha/alpha_rarefaction_assets # ========================== # Stage 2: Runtime @@ -114,52 +113,66 @@ RUN chmod 755 start_qtp-diversity.sh RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ -COPY --from=builder /opt/conda/envs/dependencies/bin/* /opt/conda/bin/ -COPY --from=builder /opt/conda/envs/dependencies/sbin/* /opt/conda/sbin/ -COPY --from=builder /opt/conda/envs/dependencies/lib/* /opt/conda/lib/ -COPY --from=builder /opt/conda/envs/dependencies/x86_64-conda-linux-gnu/* /opt/conda/x86_64-conda-linux-gnu/ -ENV PATH=$PATH:/opt/conda/bin:/opt/conda/sbin +# install tornado based trigger layer in base environment +COPY trigger_noconda.py /trigger.py + +#COPY --from=builder /opt/conda/envs/dependencies/bin/* /opt/conda/bin/ +#COPY --from=builder /opt/conda/envs/dependencies/sbin/* /opt/conda/sbin/ +#COPY --from=builder /opt/conda/envs/dependencies/lib/* /opt/conda/lib/ +#COPY --from=builder /opt/conda/envs/dependencies/x86_64-conda-linux-gnu/* /opt/conda/x86_64-conda-linux-gnu/ +#ENV PATH=$PATH:/opt/conda/bin:/opt/conda/sbin # RUN for d in `echo bin lib sbin x86_64-conda-linux-gnu`; do cp -r /dep_conda/$d/* /usr/local/$d/; done RUN ln -s /usr/local/lib/python3.8/site-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 -# # everything for unifrac -# # COPY --from=builder /opt/conda/envs/qiime2/bin/ssu /usr/local/bin/ssu -# # COPY --from=builder /opt/conda/envs/qiime2/bin/faithpd /usr/local/bin/faithpd -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libssu.so /usr/local/lib/libssu.so -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libopenblasp-r0.3.25.so /usr/local/lib/libopenblasp-r0.3.25.so -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl_cpp.so.100.1.4 /usr/local/lib/libhdf5_hl_cpp.so.100 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libgfortran.so.5.0.0 /usr/local/lib/libgfortran.so.5 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libquadmath.so.0.0.0 /usr/local/lib/libquadmath.so.0 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_cpp.so.103.2.0 /usr/local/lib/libhdf5_cpp.so.103 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl_cpp.so.100.1.4 /usr/local/lib/libhdf5_hl_cpp.so.100 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libcrypto.so.1.1 /usr/local/lib/libcrypto.so.1.1 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libcurl.so.4.8.0 /usr/local/lib/libcurl.so.4 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libnghttp2.so.14.24.1 /usr/local/lib/libnghttp2.so.14 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libssh2.so.1.0.1 /usr/local/lib/libssh2.so.1 -# # COPY --from=builder /opt/conda/envs/qiime2/lib/libssl.so.1.1 /usr/local/lib/libssl.so.1.1 -# # RUN ln -s /usr/local/lib/libopenblasp-r0.3.25.so /usr/local/lib/libcblas.so.3 -# # RUN ln -s /usr/local/lib/libopenblasp-r0.3.25.so /usr/local/lib/liblapacke.so.3 -# # RUN for f in `echo "libssu.so libhdf5_cpp.so.103 liblapacke.so.3 libcblas.so.3 libhdf5_hl_cpp.so.100 libhdf5_hl.so.100 libhdf5.so.103 libcrypto.so.1.1 libcurl.so.4 libgfortran.so.5 libnghttp2.so.14 libssh2.so.1 libssl.so.1.1 libquadmath.so.0"`; do ln -s /usr/local/lib/$f /lib/x86_64-linux-gnu/$f; done - -# # COPY trigger_noconda.py /trigger.py -# # ENV LC_ALL=C.UTF-8 -# # ENV LANG=C.UTF-8 - -# # ## Export cert and config filepaths -# # COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem -# # ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem -# # ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem - -# # #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -# # RUN chmod u+x /usr/local/bin/configure_diversity_types /usr/local/bin/start_diversity_types -# # COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -# # RUN configure_diversity_types --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` -# # RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-diversity/" /unshared_plugins/*.conf - -# # CMD ["./start_qtp-diversity.sh"] - +# everything for unifrac +COPY --from=builder /opt/conda/envs/qiime2/bin/ssu /usr/local/bin/ssu +COPY --from=builder /opt/conda/envs/qiime2/bin/faithpd /usr/local/bin/faithpd +COPY --from=builder /opt/conda/envs/qiime2/lib/libssu.so /usr/local/lib/libssu.so +COPY --from=builder /opt/conda/envs/qiime2/lib/libopenblasp-r0.3.25.so /usr/local/lib/libopenblasp-r0.3.25.so +COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl_cpp.so.100.1.4 /usr/local/lib/libhdf5_hl_cpp.so.100 +COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 +COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 +COPY --from=builder /opt/conda/envs/qiime2/lib/libgfortran.so.5.0.0 /usr/local/lib/libgfortran.so.5 +COPY --from=builder /opt/conda/envs/qiime2/lib/libquadmath.so.0.0.0 /usr/local/lib/libquadmath.so.0 +COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_cpp.so.103.2.0 /usr/local/lib/libhdf5_cpp.so.103 +COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl_cpp.so.100.1.4 /usr/local/lib/libhdf5_hl_cpp.so.100 +COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5_hl.so.100.1.3 /usr/local/lib/libhdf5_hl.so.100 +COPY --from=builder /opt/conda/envs/qiime2/lib/libhdf5.so.103.2.0 /usr/local/lib/libhdf5.so.103 +COPY --from=builder /opt/conda/envs/qiime2/lib/libcrypto.so.1.1 /usr/local/lib/libcrypto.so.1.1 +COPY --from=builder /opt/conda/envs/qiime2/lib/libcurl.so.4.8.0 /usr/local/lib/libcurl.so.4 +COPY --from=builder /opt/conda/envs/qiime2/lib/libnghttp2.so.14.24.1 /usr/local/lib/libnghttp2.so.14 +COPY --from=builder /opt/conda/envs/qiime2/lib/libssh2.so.1.0.1 /usr/local/lib/libssh2.so.1 +COPY --from=builder /opt/conda/envs/qiime2/lib/libssl.so.1.1 /usr/local/lib/libssl.so.1.1 +RUN ln -s /usr/local/lib/libopenblasp-r0.3.25.so /usr/local/lib/libcblas.so.3 +RUN ln -s /usr/local/lib/libopenblasp-r0.3.25.so /usr/local/lib/liblapacke.so.3 +RUN for f in `echo "libssu.so libhdf5_cpp.so.103 liblapacke.so.3 libcblas.so.3 libhdf5_hl_cpp.so.100 libhdf5_hl.so.100 libhdf5.so.103 libcrypto.so.1.1 libcurl.so.4 libgfortran.so.5 libnghttp2.so.14 libssh2.so.1 libssl.so.1.1 libquadmath.so.0"`; do ln -s /usr/local/lib/$f /lib/x86_64-linux-gnu/$f; done + +# fix an pandas deprecation issue, i.e. patch q2templates code +RUN sed -i "s/'display.max_colwidth', -1/'display.max_colwidth', None/" /usr/local/lib/python3.8/site-packages/q2templates/util.py + +# COPY trigger_noconda.py /trigger.py +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +# initialize qiim2 +RUN qiime + +# copy qiime2 diversity assets +COPY --from=builder /q2_diversity_assets.tgz /usr/local/lib/python3.8/site-packages/q2_diversity/q2_diversity_assets.tgz +RUN cd /usr/local/lib/python3.8/site-packages/q2_diversity && tar xzvf q2_diversity_assets.tgz + +## Export cert and config filepaths +COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem +ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem +ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem + +COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ +RUN chmod u+x /usr/local/bin/configure_diversity_types /usr/local/bin/start_diversity_types +RUN configure_diversity_types --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-diversity/" /unshared_plugins/*.conf + +# for testing +COPY test_plugin.sh /test_plugin.sh + +CMD ["./start_qtp-diversity.sh"] diff --git a/Images/qtp-diversity/requirements.txt b/Images/qtp-diversity/requirements.txt index 7e0eb3a..d56143a 100644 --- a/Images/qtp-diversity/requirements.txt +++ b/Images/qtp-diversity/requirements.txt @@ -4,6 +4,7 @@ -e /q2-taxa -e /q2-diversity -e /q2-diversity-lib +-e /q2-mislabeld -e /q2cli -e /q2templates -e /qiime2 @@ -27,6 +28,7 @@ ijson pyhmmer frictionless numpy +umap -e /unifrac -e /qtp-diversity diff --git a/Images/qtp-diversity/start_qtp-diversity.sh b/Images/qtp-diversity/start_qtp-diversity.sh index 889173f..0396871 100644 --- a/Images/qtp-diversity/start_qtp-diversity.sh +++ b/Images/qtp-diversity/start_qtp-diversity.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py qiime2 start_diversity_types /qtp-diversity +cd / && python trigger.py start_diversity_types tail -f /dev/null diff --git a/Images/test_plugin.sh b/Images/test_plugin.sh index 4426084..1a01e1e 100644 --- a/Images/test_plugin.sh +++ b/Images/test_plugin.sh @@ -19,11 +19,17 @@ for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name "testing sed -i 's|URL = "https://localhost:8383"|URL = "https://tinqiita-qiita-1:21174"|' $f; done -# fix qiita base url in plugin tests +# fix qiita base url in qtp-sequencing plugin tests for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do sed -i 's|https://localhost:21174|https://tinqiita-qiita-1:21174|' $f; done +# fix qiita base url in qtp-diversity plugin tests +for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do + sed -i "s|plugin('https://localhost:8383', 'register', 'ignored')|plugin('https://tinqiita-nginx-1:8383', 'register', 'ignored')|" $f; +done + + # better save than sorry export QIITA_PORT=21174 export QIITA_ROOTCA_CERT=$SSL_CERT_FILE From 80488d96989896da3d8c029c3512a04d019b2e68 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 08:39:02 +0200 Subject: [PATCH 241/287] forgot to add qtp-diversity to build matrix --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 625d6f0..54a1d5b 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", + plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "nginx", "qiita", "plugin_collector" ] runs-on: ubuntu-latest From 6b3a687a9ee895cef1b09b7e068bf978461e31c6 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 08:58:18 +0200 Subject: [PATCH 242/287] generalize quotes to match multiple cases --- Images/test_plugin.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Images/test_plugin.sh b/Images/test_plugin.sh index 1a01e1e..9b95dde 100644 --- a/Images/test_plugin.sh +++ b/Images/test_plugin.sh @@ -24,9 +24,9 @@ for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do sed -i 's|https://localhost:21174|https://tinqiita-qiita-1:21174|' $f; done -# fix qiita base url in qtp-diversity plugin tests +# fix qiita base url in qtp-diversity plugin tests. Use . instead of " or ' to be more general for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do - sed -i "s|plugin('https://localhost:8383', 'register', 'ignored')|plugin('https://tinqiita-nginx-1:8383', 'register', 'ignored')|" $f; + sed -i "s|plugin(.https://localhost:8383., .register., .ignored.)|plugin('https://tinqiita-nginx-1:8383', 'register', 'ignored')|" $f; done From 7b09673e3c8816f61946e3d8d97e6efb5dceb608 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 08:58:35 +0200 Subject: [PATCH 243/287] add test script --- Images/qp-deblur/qp-deblur.dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 0d24d91..3e64723 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -133,5 +133,8 @@ RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-d # remove conda command from tigger.py RUN sed -i "s|source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s;||" /trigger.py && sed -i "s|conda_env_name, ||" /trigger.py +# for testing +COPY test_plugin.sh /test_plugin.sh + CMD ["./start_qp-deblur.sh"] # ^^ 848 MB \ No newline at end of file From cc085f1e9060e32e8aa6ff0d9cdc7540e687e938 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 10:55:55 +0200 Subject: [PATCH 244/287] "patch" qtp-biom tests --- Images/test_plugin.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Images/test_plugin.sh b/Images/test_plugin.sh index 9b95dde..93ad1b8 100644 --- a/Images/test_plugin.sh +++ b/Images/test_plugin.sh @@ -27,9 +27,10 @@ done # fix qiita base url in qtp-diversity plugin tests. Use . instead of " or ' to be more general for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do sed -i "s|plugin(.https://localhost:8383., .register., .ignored.)|plugin('https://tinqiita-nginx-1:8383', 'register', 'ignored')|" $f; + # below seen in qtp-biom + sed -i "s|plugin("https://localhost:8383", job_id, self.out_dir)|plugin("https://tinqiita-nginx-1:8383", job_id, self.out_dir)|" $f; done - # better save than sorry export QIITA_PORT=21174 export QIITA_ROOTCA_CERT=$SSL_CERT_FILE From 238aa2f46963e30436bf12ece1f6414fccde9b79 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 18:17:48 +0200 Subject: [PATCH 245/287] ensure db re-populate does not destroy conda startup scripts --- Images/qiita/qiita.dockerfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index 53f5fe4..f3e0ca5 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -1,4 +1,4 @@ -# VERSION: 2025.09.02 +# VERSION: 2025.09.09 FROM ubuntu:24.04 @@ -51,6 +51,11 @@ RUN pip install \ # RUN git clone -b master https://github.com/qiita-spots/qiita.git RUN git clone -b auth_oidc https://github.com/jlab/qiita.git +# should tests re-populate the DB, ensure private plugin, qtp-biom and qp-target-gene use the correct conda env +RUN sed -i "s|'source /home/runner/.profile; conda activate qiita'|'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qiita'|" /qiita/qiita_db/support_files/populate_test_db.sql +RUN sed -i "s|'source ~/virtualenv/python2.7/bin/activate; export PATH=\$HOME/miniconda3/bin/:\$PATH; . activate qtp-biom'|'true'|" /qiita/qiita_db/support_files/populate_test_db.sql +RUN sed -i "s|'source activate qiita'|'true'|" /qiita/qiita_db/support_files/populate_test_db.sql + # We need to install necessary dependencies # as well as some extra dependencies for psycopg2 to work RUN git clone https://github.com/psycopg/psycopg2.git From bc9661c80ae2bd18dafc9bdbf7073d69dd9b4b4a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 18:18:25 +0200 Subject: [PATCH 246/287] escape " and ' --- Images/test_plugin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/test_plugin.sh b/Images/test_plugin.sh index 93ad1b8..e50861c 100644 --- a/Images/test_plugin.sh +++ b/Images/test_plugin.sh @@ -28,7 +28,7 @@ done for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do sed -i "s|plugin(.https://localhost:8383., .register., .ignored.)|plugin('https://tinqiita-nginx-1:8383', 'register', 'ignored')|" $f; # below seen in qtp-biom - sed -i "s|plugin("https://localhost:8383", job_id, self.out_dir)|plugin("https://tinqiita-nginx-1:8383", job_id, self.out_dir)|" $f; + sed -i 's|plugin("https://localhost:8383", job_id, self.out_dir)|plugin("https://tinqiita-nginx-1:8383", job_id, self.out_dir)|' $f; done # better save than sorry From 48f0b48697b37538f812468b301ec8f1951cd154 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 18:18:37 +0200 Subject: [PATCH 247/287] move requirements into file --- Images/qtp-biom/requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Images/qtp-biom/requirements.txt b/Images/qtp-biom/requirements.txt index 3c7bb3d..930e5eb 100644 --- a/Images/qtp-biom/requirements.txt +++ b/Images/qtp-biom/requirements.txt @@ -24,6 +24,8 @@ pyhmmer frictionless numpy iow +tornado +pip-system-certs -e /qtp-biom -e /qiita-files From a497b098d4c07341eecaf17a446d12ef82f0bb68 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 18:18:58 +0200 Subject: [PATCH 248/287] a little easier --- Images/qtp-biom/qtp-biom.dockerfile | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index 1346a6c..cae82a5 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -32,8 +32,7 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ # install tornado based trigger layer in base environment RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py +# RUN conda install tornado # Download qtp-biom yaml # RUN wget https://raw.githubusercontent.com/qiime2/distributions/refs/heads/dev/${QIIME2RELEASE}/tiny/released/qiime2-tiny-ubuntu-latest-conda.yml @@ -75,8 +74,7 @@ RUN sed -i "s|'qiita_client/archive/master.zip'||" setup.py RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs -RUN conda install tornado -COPY trigger.py /trigger.py +#RUN conda install tornado # TODO: should the plugin get the server configuration?! RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg @@ -133,7 +131,7 @@ COPY --from=builder /opt/conda/envs/qtp-biom/lib/python3.8/site-packages/bp /usr RUN ln -s /usr/local/lib/python3.8/site-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0 /lib/x86_64-linux-gnu/libgomp.so.1 # install tornado based trigger layer in base environment -RUN pip install -U --no-cache-dir tornado +#RUN pip install -U --no-cache-dir tornado COPY trigger_noconda.py /trigger.py WORKDIR / @@ -144,10 +142,10 @@ RUN chmod 755 start_qtp-biom.sh RUN mkdir -p /unshared_plugins ENV QIITA_PLUGINS_DIR=/unshared_plugins/ -RUN pip install pip-system-certs +# RUN pip install pip-system-certs -RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/configure_biom -RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/start_biom +#RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/configure_biom +#RUN sed -i "s|^#\!.*|#\!/usr/local/bin/python|" /usr/local/bin/start_biom # use git branch instead of pypi version (stored via wheel) #COPY --from=builder /qiita_client /qiita_client @@ -158,9 +156,9 @@ COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certi ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem -RUN mkdir -p /qiita_server_certificates/ +#RUN mkdir -p /qiita_server_certificates/ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /usr/local/bin/configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN configure_biom --env-script "true" --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-biom/" /unshared_plugins/*.conf # fix an pandas deprecation issue, i.e. patch q2templates code From 721f745cc6cabd159cc5a2046faaefb107dd6778 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Tue, 9 Sep 2025 18:20:06 +0200 Subject: [PATCH 249/287] trigger all but old q1.9 --- .github/workflows/buildContainer.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 54a1d5b..9e9a4ad 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,8 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qp-target-gene", "qtp-sequencing", "qtp-visualization", "qtp-diversity", + plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", + # "qp-target-gene", "nginx", "qiita", "plugin_collector" ] runs-on: ubuntu-latest From cd1382f9785e669a414fd307ef4de002010efedd Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 12:18:59 +0200 Subject: [PATCH 250/287] extra work due to py2 py3 differences --- Images/test_plugin.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Images/test_plugin.sh b/Images/test_plugin.sh index e50861c..41fd169 100644 --- a/Images/test_plugin.sh +++ b/Images/test_plugin.sh @@ -5,7 +5,11 @@ echo "plugin to be tested is: '$PLUGIN'" # install dependencies apt-get update apt-get -y --fix-missing install git -pip install pytest +if [ "qp-target-gene" == "$PLUGIN" ]; then + REQUESTS_CA_BUNDLE="" pip2 install "pytest<5"; +else + REQUESTS_CA_BUNDLE="" pip install pytest; +fi; # clone plugin repository git clone https://github.com/qiita-spots/${PLUGIN} @@ -15,13 +19,15 @@ git clone https://github.com/qiita-spots/${PLUGIN} # go through nginx! # fix qiita base url in client -for f in `find /usr/local/lib/python*/site-packages/qiita_client/ -name "testing.py"`; do +for f in `find /usr/local/lib/python*/site-packages/qiita_client/ /usr/local/lib/python*/dist-packages/qiita_client/ -name "testing.py"`; do sed -i 's|URL = "https://localhost:8383"|URL = "https://tinqiita-qiita-1:21174"|' $f; done # fix qiita base url in qtp-sequencing plugin tests for f in `find /${PLUGIN}/*/tests/ -name 'test_*.py'`; do sed -i 's|https://localhost:21174|https://tinqiita-qiita-1:21174|' $f; + # below seen in qp-target-gene + sed -i 's|plugin("https://localhost:21174", .register., .ignored.)|plugin("https://tinqiita-qiita-1:21174", "register", "ignored")|' $f; done # fix qiita base url in qtp-diversity plugin tests. Use . instead of " or ' to be more general From 28957acc14945e30fc11dfc0179937a7c022af91 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 12:20:12 +0200 Subject: [PATCH 251/287] make qp-target-gene work --- .github/workflows/buildContainer.yaml | 2 +- Images/qiita/qiita.dockerfile | 3 +++ .../qp-target-gene/qp-target-gene.dockerfile | 25 +++++++++++++------ Images/qp-target-gene/requirements.txt | 1 + Makefile | 15 +++++++++-- compose.yaml | 2 ++ compose_github.yaml | 1 + 7 files changed, 38 insertions(+), 11 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 9e9a4ad..4107948 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -40,7 +40,7 @@ jobs: - name: Make tinqiita targets # second copy of "qiita_server_certificates" is necessary to match path for docker build, first copy for mounting into container run: | - make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./environments/qiita_db.env ./environments/qiita.env config + make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./references/qp-target-gene ./environments/qiita_db.env ./environments/qiita.env config cp -r ./references/qiita_server_certificates ./qiita_server_certificates - name: Build Image (but do not push yet) diff --git a/Images/qiita/qiita.dockerfile b/Images/qiita/qiita.dockerfile index f3e0ca5..0a1ab71 100644 --- a/Images/qiita/qiita.dockerfile +++ b/Images/qiita/qiita.dockerfile @@ -56,6 +56,9 @@ RUN sed -i "s|'source /home/runner/.profile; conda activate qiita'|'source /opt/ RUN sed -i "s|'source ~/virtualenv/python2.7/bin/activate; export PATH=\$HOME/miniconda3/bin/:\$PATH; . activate qtp-biom'|'true'|" /qiita/qiita_db/support_files/populate_test_db.sql RUN sed -i "s|'source activate qiita'|'true'|" /qiita/qiita_db/support_files/populate_test_db.sql +# there seems to be a conflict with parameter names für qp-target-gene. See: https://github.com/qiita-spots/qp-target-gene/issues/24 +RUN sed -i "s|'1.9.1',|'1.9.hide',|" /qiita/qiita_db/support_files/populate_test_db.sql + # We need to install necessary dependencies # as well as some extra dependencies for psycopg2 to work RUN git clone https://github.com/psycopg/psycopg2.git diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index 3b998c8..c8272b0 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -45,7 +45,7 @@ RUN python2.7 get-pip2.7.py --force-reinstall RUN pip install -U pip #RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip RUN git clone -b master https://github.com/qiita-spots/qiita_client.git -RUN cd qiita_client && pip install --no-cache-dir . +RUN cd /qiita_client && pip install --no-cache-dir . RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip RUN git clone https://github.com/qiita-spots/qp-target-gene.git @@ -57,9 +57,19 @@ RUN pip install pip-system-certs WORKDIR / +# qiime 1.9.1 comes with https://pypi.org/project/qiime-default-reference/ as dependency, which is ~184MB +# we "hide" it here, as necessary files will be downloaded from ftp.microbio.me/greengenes_release while setting up qiita anyway +RUN pip download --dest /qiime_default_reference qiime_default_reference \ + && cd /qiime_default_reference \ + && tar xzvf *.tar.gz \ + && cd qiime-default-reference-0.1.3 \ + && for fzip in `find . -type f -name "97*"`; do fplain=`echo $fzip | sed "s|.gz$||g"`; echo "content erased to generate small wheel file, as reference shall be mounted to target container later on." > $fplain; gzip -f $fplain; done + COPY requirements.txt ./requirements.txt RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt +# download sortmerna / index_db sources for version 2.0 and re-compile statically as different glibc and libstdc++ couse issues +RUN wget https://github.com/sortmerna/sortmerna/archive/refs/tags/2.0.tar.gz && tar xzvf 2.0.tar.gz && cd /sortmerna-2.0 && ./configure LDFLAGS=" -static " && make -j # ========================== # Stage 2: Runtime @@ -73,23 +83,18 @@ RUN mkdir -p /usr/share/man/man1 && \ apt-get install -y --no-install-recommends python2 python3 curl python-tk && \ rm -rf /var/lib/apt/lists/* -# # RUN apk add --no-cache python2 python3 curl - -# pip2 installieren +# install pip2 COPY --from=builder /get-pip2.7.py /get-pip3.7.py / RUN python2 get-pip2.7.py \ && rm get-pip2.7.py -# pip3 installieren +# install pip3 RUN python3 get-pip3.7.py \ && rm get-pip3.7.py # python package compile in build stage COPY --from=builder /wheels /wheels -# dependent binaries + necessary libraries: sortmerna -COPY --from=builder /opt/conda/envs/qp-target-gene/bin/indexdb_rna /opt/conda/envs/qp-target-gene/bin/sortmerna /usr/local/bin/ - RUN pip2 install --no-cache-dir /wheels/* \ && rm -rf rm -rf `find /usr/local/lib/python2.7/site-packages -type d -name "tests" | grep -v numpy` COPY --from=builder /opt/conda/envs/qp-target-gene/lib/libpython2.7.so.1.0 /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 @@ -106,6 +111,10 @@ ENV QIITA_PLUGINS_DIR=/unshared_plugins/ RUN pip3 install tornado COPY trigger_noconda.py /trigger.py +# copy sortmerna binaries +COPY --from=builder /sortmerna-2.0/sortmerna /usr/local/bin/sortmerna +COPY --from=builder /sortmerna-2.0/indexdb_rna /usr/local/bin/indexdb_rna + ## Export cert and config filepaths COPY qiita_server_certificates/qiita_server_certificates.pem /qiita_server_certificates/qiita_server_certificates.pem ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem diff --git a/Images/qp-target-gene/requirements.txt b/Images/qp-target-gene/requirements.txt index 8c07d47..52ed9a5 100644 --- a/Images/qp-target-gene/requirements.txt +++ b/Images/qp-target-gene/requirements.txt @@ -1,3 +1,4 @@ +-e /qiime_default_reference/qiime-default-reference-0.1.3 pip-system-certs https://github.com/qiita-spots/qiita-files/archive/master.zip diff --git a/Makefile b/Makefile index d85d9da..d62adfb 100644 --- a/Makefile +++ b/Makefile @@ -47,9 +47,20 @@ plugin: Images/trigger.py Images/trigger_noconda.py $(DIR_REFERENCES)/qiita_serv $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qp-target-gene: Images/qp-target-gene/qp-target-gene.dockerfile Images/qp-target-gene/start_qp-target-gene.sh Images/qp-target-gene/requirements.txt +# download GG13.8 reference sets from ftp://ftp.microbio.me/greengenes_release/gg_13_8_otus, instead of storing these large files within the qp-target-gene image 149 MB +$(DIR_REFERENCES)/qp-target-gene: + mkdir -p $(DIR_REFERENCES)/qp-target-gene + echo '56ef15dccf2e931ec173f4f977ed649b 97_otu_taxonomy.txt' > $(DIR_REFERENCES)/qp-target-gene/exp.md5 + echo '50b2269712b3738afb41892bed936c29 97_otus.fasta' >> $(DIR_REFERENCES)/qp-target-gene/exp.md5 + echo 'b7e76593bce82913af1cfb06edf15732 97_otus.tree' >> $(DIR_REFERENCES)/qp-target-gene/exp.md5 + wget 'ftp://ftp.microbio.me/greengenes_release/gg_13_8_otus/trees/97_otus.tree' -O $(DIR_REFERENCES)/qp-target-gene/97_otus.tree + wget 'ftp://ftp.microbio.me/greengenes_release/gg_13_8_otus/taxonomy/97_otu_taxonomy.txt' -O $(DIR_REFERENCES)/qp-target-gene/97_otu_taxonomy.txt + wget 'ftp://ftp.microbio.me/greengenes_release/gg_13_8_otus/rep_set/97_otus.fasta' -O $(DIR_REFERENCES)/qp-target-gene/97_otus.fasta + cd $(DIR_REFERENCES)/qp-target-gene/ && md5sum -c exp.md5 || rm -rf $(DIR_REFERENCES)/qp-target-gene/ + +.built_image_qp-target-gene: Images/qp-target-gene/qp-target-gene.dockerfile Images/qp-target-gene/start_qp-target-gene.sh $(DIR_REFERENCES)/qp-target-gene Images/qp-target-gene/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin - cp $^ $(TMPDIR) + cp -r $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` diff --git a/compose.yaml b/compose.yaml index 55ecbf5..53a4b4d 100644 --- a/compose.yaml +++ b/compose.yaml @@ -235,6 +235,7 @@ services: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates - test_tmp_dir:/tmp + - ./references/qp-target-gene:/databases/gg/13_8/rep_set environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: @@ -355,6 +356,7 @@ services: condition: service_started environment: - QIITA_PLUGINS="qtp-biom:qtp-sequencing:qp-target-gene:qtp-visualization:qtp-diversity:qp-deblur:qp-qiime2:qtp-job-output-folder:" + #- QIITA_PLUGINS="qp-target-gene:" command: ['/start_plugin_collector.sh'] networks: diff --git a/compose_github.yaml b/compose_github.yaml index 6223412..ddb6791 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -218,6 +218,7 @@ services: - qiita-data:/qiita_data - ./references/qiita_server_certificates:/qiita_server_certificates - test_tmp_dir:/tmp + - ./references/qp-target-gene:/databases/gg/13_8/rep_set environment: - QIITA_CLIENT_DEBUG_LEVEL=DEBUG networks: From 890b1357d24eb739130679919bc1878a08f0ae54 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 12:56:17 +0200 Subject: [PATCH 252/287] also build qp-target-gene --- .github/workflows/buildContainer.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 4107948..3a95d3d 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,8 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", - # "qp-target-gene", + plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "nginx", "qiita", "plugin_collector" ] runs-on: ubuntu-latest From 20162ac6dda3a8df86133cbe58b284ab0a0d5861 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 13:41:35 +0200 Subject: [PATCH 253/287] shrink qtp-job-output-folder --- .../qtp-job-output-folder.dockerfile | 50 +++++++++++++++---- .../start_qtp-job-output-folder.sh | 2 +- Makefile | 2 +- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile index 0d92840..659b1bb 100644 --- a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile +++ b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile @@ -1,4 +1,9 @@ -FROM ubuntu:24.04 +# VERSION: 2025.09.11 + +# ========================== +# Stage 1: Build wheels +# ========================== +FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 @@ -25,8 +30,6 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ # install tornado based trigger layer in base environment RUN pip install -U pip -RUN conda install tornado -COPY trigger.py /trigger.py # Create conda env RUN conda create --name qtp-job-output-folder -y python=3.6 pip==9.0.3 @@ -35,16 +38,40 @@ RUN conda create --name qtp-job-output-folder -y python=3.6 pip==9.0.3 SHELL ["conda", "run", "-p", "/opt/conda/envs/qtp-job-output-folder", "/bin/bash", "-c"] RUN pip install -U pip + +#RUN pip install https://github.com/qiita-spots/qiita_client/archive/master.zip +RUN git clone -b master https://github.com/qiita-spots/qiita_client.git +RUN cd qiita_client && pip install --no-cache-dir . + +# RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip +RUN git clone -b master https://github.com/qiita-spots/qiita-files.git +RUN cd /qiita-files && pip install -e . -v + RUN git clone https://github.com/qiita-spots/qtp-job-output-folder.git WORKDIR /qtp-job-output-folder +RUN sed -i "s|'qiita-files @ https://github.com/'||" setup.py +RUN sed -i "s|'qiita-spots/qiita-files/archive/master.zip',||" setup.py +RUN sed -i "s|'qiita_client @ https://github.com/'||" setup.py +RUN sed -i "s|'qiita-spots/qiita_client/archive/master.zip'||" setup.py RUN pip install -e . -RUN pip install --upgrade certifi -RUN pip install pip-system-certs - -# TODO: should the plugin get the server configuration?! -RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg WORKDIR / +COPY requirements.txt /requirements.txt +RUN pip wheel --no-cache-dir --wheel-dir /wheels -r /requirements.txt + + +# ========================== +# Stage 2: Runtime +# ========================== +FROM python:3.6-slim + +# python package compile in build stage +COPY --from=builder /wheels /wheels + +RUN pip install --no-cache-dir /wheels/* \ + && rm -rf rm -rf `find /usr/local/lib/python3.6/site-packages -type d -name "tests" | grep -v numpy` + +COPY trigger_noconda.py /trigger.py COPY start_qtp-job-output-folder.sh . RUN chmod 755 start_qtp-job-output-folder.sh @@ -58,9 +85,12 @@ ENV REQUESTS_CA_BUNDLE=/qiita_server_certificates/qiita_server_certificates.pem ENV SSL_CERT_FILE=/qiita_server_certificates/qiita_server_certificates.pem #RUN export QIITA_ROOTCA_CERT=/unshared_certificates/ci_rootca.crt -RUN chmod u+x /qtp-job-output-folder/scripts/configure_qtp_job_output_folder /qtp-job-output-folder/scripts/start_qtp_job_output_folder +RUN chmod u+x /usr/local/bin/configure_qtp_job_output_folder /usr/local/bin/start_qtp_job_output_folder COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ -RUN /qtp-job-output-folder/scripts/configure_qtp_job_output_folder --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` +RUN configure_qtp_job_output_folder --env-script "true" --ca-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qtp-job-output-folder/" /unshared_plugins/*.conf +# for testing +COPY test_plugin.sh /test_plugin.sh + CMD ["./start_qtp-job-output-folder.sh"] diff --git a/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh b/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh index cdc5f27..d3097cb 100644 --- a/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh +++ b/Images/qtp-job-output-folder/start_qtp-job-output-folder.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd / && python trigger.py qtp-job-output-folder start_qtp_job_output_folder /qtp-job-output-folder +cd / && python trigger.py start_qtp_job_output_folder tail -f /dev/null diff --git a/Makefile b/Makefile index d62adfb..37eb050 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ $(DIR_REFERENCES)/qp-deblur/reference-gg-raxml-bl.tre: $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` touch .built_image_`basename $< | cut -d "." -f 1` -.built_image_qtp-job-output-folder: Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile Images/qtp-job-output-folder/start_qtp-job-output-folder.sh +.built_image_qtp-job-output-folder: Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile Images/qtp-job-output-folder/start_qtp-job-output-folder.sh Images/qtp-job-output-folder/requirements.txt tmpdir=$(TMPDIR) $(MAKE) plugin cp $^ $(TMPDIR) $(PODMAN_BIN) build $(TMPDIR)/ -f $(TMPDIR)/`basename $<` $(PODMAN_FLAGS) -t local-`basename $< | cut -d "." -f 1` From 4b0cc58e7562c2acd16df48576a60bee88a41b02 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 13:42:20 +0200 Subject: [PATCH 254/287] add qtp-job-output-folder --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 3a95d3d..6112c90 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -9,7 +9,7 @@ jobs: docker: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", + plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", "nginx", "qiita", "plugin_collector" ] runs-on: ubuntu-latest From f2fac482677ff2cb2843a31a97ea3280f5967137 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 13:44:29 +0200 Subject: [PATCH 255/287] added missing file --- Images/qtp-job-output-folder/requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Images/qtp-job-output-folder/requirements.txt diff --git a/Images/qtp-job-output-folder/requirements.txt b/Images/qtp-job-output-folder/requirements.txt new file mode 100644 index 0000000..d56395f --- /dev/null +++ b/Images/qtp-job-output-folder/requirements.txt @@ -0,0 +1,6 @@ +tornado +pip-system-certs + +-e /qiita_client +-e /qiita-files +-e /qtp-job-output-folder From fcd3dd6782200254c5728ce645eb4795892bed22 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 14:32:42 +0200 Subject: [PATCH 256/287] add plugin name as env --- Images/qp-deblur/qp-deblur.dockerfile | 3 +++ Images/qp-target-gene/qp-target-gene.dockerfile | 3 +++ Images/qtp-biom/qtp-biom.dockerfile | 3 +++ Images/qtp-diversity/qtp-diversity.dockerfile | 5 +++++ .../qtp-job-output-folder/qtp-job-output-folder.dockerfile | 3 +++ Images/qtp-sequencing/qtp-sequencing.dockerfile | 3 +++ Images/qtp-visualization/qtp-visualization.dockerfile | 3 +++ 7 files changed, 23 insertions(+) diff --git a/Images/qp-deblur/qp-deblur.dockerfile b/Images/qp-deblur/qp-deblur.dockerfile index 3e64723..067fe51 100644 --- a/Images/qp-deblur/qp-deblur.dockerfile +++ b/Images/qp-deblur/qp-deblur.dockerfile @@ -61,6 +61,9 @@ RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt FROM python:3.5-slim # ^^ 110 MB +# let the container know it's plugin name +ENV PLUGIN=qp-deblur + # deblur dependent binaries + necessary libraries: mafft, vsearch, sortmerna COPY --from=builder /opt/conda/envs/deblur/bin/mafft /opt/conda/envs/deblur/bin/vsearch /opt/conda/envs/deblur/bin/indexdb_rna /opt/conda/envs/deblur/bin/sortmerna /usr/local/bin/ # ^^ 113 MB diff --git a/Images/qp-target-gene/qp-target-gene.dockerfile b/Images/qp-target-gene/qp-target-gene.dockerfile index c8272b0..dc3b9f7 100644 --- a/Images/qp-target-gene/qp-target-gene.dockerfile +++ b/Images/qp-target-gene/qp-target-gene.dockerfile @@ -77,6 +77,9 @@ RUN wget https://github.com/sortmerna/sortmerna/archive/refs/tags/2.0.tar.gz && # I am testing ubuntu as base image, since python:xxx-slim was too hard/large to install python2 and python3 side by side FROM ubuntu:22.04 +# let the container know it's plugin name +ENV PLUGIN=qp-target-gene + # py2 and py3 RUN mkdir -p /usr/share/man/man1 && \ apt-get update && \ diff --git a/Images/qtp-biom/qtp-biom.dockerfile b/Images/qtp-biom/qtp-biom.dockerfile index cae82a5..98d4841 100644 --- a/Images/qtp-biom/qtp-biom.dockerfile +++ b/Images/qtp-biom/qtp-biom.dockerfile @@ -120,6 +120,9 @@ CMD ["./start_qtp-biom.sh"] # ========================== FROM python:3.8-slim +# let the container know it's plugin name +ENV PLUGIN=qtp-biom + # python package compile in build stage COPY --from=builder /wheels /wheels diff --git a/Images/qtp-diversity/qtp-diversity.dockerfile b/Images/qtp-diversity/qtp-diversity.dockerfile index 0ce792d..f7d79cc 100644 --- a/Images/qtp-diversity/qtp-diversity.dockerfile +++ b/Images/qtp-diversity/qtp-diversity.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.09.11 + FROM ubuntu:24.04 AS builder ARG MINIFORGE_VERSION=24.1.2-0 @@ -101,6 +103,9 @@ RUN cd /opt/conda/envs/qiime2/lib/python3.8/site-packages/q2_diversity/ && tar c # ========================== FROM python:3.8-slim +# let the container know it's plugin name +ENV PLUGIN=qtp-diversity + # python package compile in build stage COPY --from=builder /wheels /wheels diff --git a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile index 659b1bb..3ea824a 100644 --- a/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile +++ b/Images/qtp-job-output-folder/qtp-job-output-folder.dockerfile @@ -65,6 +65,9 @@ RUN pip wheel --no-cache-dir --wheel-dir /wheels -r /requirements.txt # ========================== FROM python:3.6-slim +# let the container know it's plugin name +ENV PLUGIN=qtp-job-output-folder + # python package compile in build stage COPY --from=builder /wheels /wheels diff --git a/Images/qtp-sequencing/qtp-sequencing.dockerfile b/Images/qtp-sequencing/qtp-sequencing.dockerfile index b6d976f..20cbd1d 100644 --- a/Images/qtp-sequencing/qtp-sequencing.dockerfile +++ b/Images/qtp-sequencing/qtp-sequencing.dockerfile @@ -61,6 +61,9 @@ RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt # ========================== FROM python:3.9-slim +# let the container know it's plugin name +ENV PLUGIN=qtp-sequencing + # python package compile in build stage COPY --from=builder /wheels /wheels diff --git a/Images/qtp-visualization/qtp-visualization.dockerfile b/Images/qtp-visualization/qtp-visualization.dockerfile index 53b1d5b..e08ad3e 100644 --- a/Images/qtp-visualization/qtp-visualization.dockerfile +++ b/Images/qtp-visualization/qtp-visualization.dockerfile @@ -87,6 +87,9 @@ RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt # ========================== FROM python:3.8-slim +# let the container know it's plugin name +ENV PLUGIN=qtp-visualization + # python package compile in build stage COPY --from=builder /wheels /wheels From 0517653c320cc593eaa1651157fda9cd0b4f92c2 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 16:09:27 +0200 Subject: [PATCH 257/287] bring conda back in trigger.py --- Images/trigger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/trigger.py b/Images/trigger.py index 666be08..9293396 100644 --- a/Images/trigger.py +++ b/Images/trigger.py @@ -28,7 +28,7 @@ async def post(self): return # Systembefehl ausfuehren - cmd = '%s %s %s %s' % (plugin_start_script, qiita_worker_url, job_id, output_dir) + cmd = 'source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/%s; %s/scripts/%s %s %s %s' % (conda_env_name, plugin_src_dir, plugin_start_script, qiita_worker_url, job_id, output_dir) # Asynchronen Subprozess starten proc = await asyncio.create_subprocess_shell( cmd, From f275fcd6b51a98cd91ba7eb29b9c5a5ee40b213b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 16:09:42 +0200 Subject: [PATCH 258/287] adapt for qiime2 tests, which is still based on conda --- Images/test_plugin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Images/test_plugin.sh b/Images/test_plugin.sh index 41fd169..a7eaa10 100644 --- a/Images/test_plugin.sh +++ b/Images/test_plugin.sh @@ -19,7 +19,7 @@ git clone https://github.com/qiita-spots/${PLUGIN} # go through nginx! # fix qiita base url in client -for f in `find /usr/local/lib/python*/site-packages/qiita_client/ /usr/local/lib/python*/dist-packages/qiita_client/ -name "testing.py"`; do +for f in `find /usr/local/lib/python*/site-packages/qiita_client/ /usr/local/lib/python*/dist-packages/qiita_client/ /opt/conda/envs/qiime2/lib/python3.8/site-packages/qiita_client/ -name "testing.py"`; do sed -i 's|URL = "https://localhost:8383"|URL = "https://tinqiita-qiita-1:21174"|' $f; done From 9cd09b85d8507c5ba164d59e8da5fe8ccf3c88b9 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 16:10:05 +0200 Subject: [PATCH 259/287] ready for testing --- Images/qp-qiime2/qp-qiime2.dockerfile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Images/qp-qiime2/qp-qiime2.dockerfile b/Images/qp-qiime2/qp-qiime2.dockerfile index 3a63ce5..6f63281 100644 --- a/Images/qp-qiime2/qp-qiime2.dockerfile +++ b/Images/qp-qiime2/qp-qiime2.dockerfile @@ -44,7 +44,10 @@ RUN pip install https://github.com/qiita-spots/qiita-files/archive/master.zip RUN pip install https://github.com/biocore/q2-mislabeled/archive/refs/heads/main.zip RUN pip install q2-umap q2-greengenes2 RUN git clone https://github.com/qiita-spots/qp-qiime2.git -WORKDIR qp-qiime2 +WORKDIR /qp-qiime2 + +RUN sed -i "s|self.basedir, '..', '..', '|'/|g" /qp-qiime2/qp_qiime2/tests/test_qiime2.py + RUN pip install -e . RUN pip install --upgrade certifi RUN pip install pip-system-certs @@ -63,6 +66,9 @@ RUN export QP_QIIME2_FILTER_QZA=/filtering/ # TODO: should the plugin get the server configuration?! RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg +# let the container know it's plugin name +ENV PLUGIN=qp-qiime2 + WORKDIR / COPY start_qp-qiime2.sh . @@ -84,4 +90,7 @@ COPY qiita_server_certificates/*_server.* /qiita_server_certificates/ RUN /qp-qiime2/scripts/configure_qiime2 --env-script 'true' --server-cert `find /qiita_server_certificates/ -name "*_server.crt" -type f` RUN sed -i -E "s/^START_SCRIPT = .+/START_SCRIPT = python \/start_plugin.py qp-qiime2/" /unshared_plugins/*.conf +# for testing +COPY test_plugin.sh /test_plugin.sh + CMD ["./start_qp-qiime2.sh"] From 2d216f7784fb3b87d312be143cdaba51399ca46a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 16:28:31 +0200 Subject: [PATCH 260/287] test 1 --- .github/workflows/buildContainer.yaml | 158 +++++++++++++++++--------- 1 file changed, 106 insertions(+), 52 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 6112c90..f047057 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -3,85 +3,139 @@ name: docker on: push: branches: - - 'smaller_deblur' + - 'restructure_github_actions' jobs: - docker: + build_main: strategy: matrix: - plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", - "nginx", "qiita", "plugin_collector" - ] + container: ["nginx", "qiita", "plugin_collector"] runs-on: ubuntu-latest steps: - - name: Checkout repository + - name: Checkout tinqiita repo uses: actions/checkout@v4 - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - registry: harbor.computational.bio.uni-giessen.de - username: ${{ vars.HARBOR_CB_USERNAME }} - password: ${{ secrets.HARBOR_CB_SECRET }} - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Read version from file + - name: Read image version from dockerfile id: vars run: | - VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + VERSION=$(head -n 1 Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/trigger_noconda.py Images/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . + cp Images/${{ matrix.container }}/start_${{ matrix.container }}.sh Images/test_plugin.sh Images/nginx/nginx_qiita.conf Images/${{ matrix.container }}/requirements.txt . cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . - - name: Make tinqiita targets + - name: Create certificate and fake reference databases # second copy of "qiita_server_certificates" is necessary to match path for docker build, first copy for mounting into container run: | - make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./references/qp-target-gene ./environments/qiita_db.env ./environments/qiita.env config + make ./references/qiita_server_certificates ./environments/qiita_db.env ./environments/qiita.env config + mkdir -p ./references/qp-deblur/ ./references/qp-target-gene + for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done cp -r ./references/qiita_server_certificates ./qiita_server_certificates - - name: Build Image (but do not push yet) + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build main qiita Images and push to github's own registry uses: docker/build-push-action@v6 with: context: . push: false load: true - file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - tags: tinqiita/${{ matrix.plugin }}:testcandidate + file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile + tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate + +# build_plugins: +# needs: build_main +# strategy: +# matrix: +# container: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder"] +# runs-on: ubuntu-latest +# steps: - - name: debug docker - run: | - docker image ls -a - docker ps -a +# jobs: +# docker: +# strategy: +# matrix: +# plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", +# "nginx", "qiita", "plugin_collector" +# ] +# runs-on: ubuntu-latest +# steps: +# - name: Checkout repository +# uses: actions/checkout@v4 - - name: adapt compose file to select specific plugin - run: | - sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml - sed -i "s|image: janssenlab/${{ matrix.plugin }}:latest|image: tinqiita/${{ matrix.plugin }}:testcandidate|" compose_github.yaml +# - name: Login to DockerHub +# uses: docker/login-action@v3 +# with: +# registry: harbor.computational.bio.uni-giessen.de +# username: ${{ vars.HARBOR_CB_USERNAME }} +# password: ${{ secrets.HARBOR_CB_SECRET }} - - name: Run docker compose - if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} - uses: hoverkraft-tech/compose-action@v2.0.1 - with: - compose-file: "compose_github.yaml" - services: | - nginx - - name: Execute tests in the running services (wait till qiita plugins are registered) - if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} - run: | - sleep 5 - docker compose exec qiita /bin/bash -c "cat /logs/*; cat /qiita_plugins/*" - docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_plugin.sh" +# - name: Set up Docker Buildx +# uses: docker/setup-buildx-action@v3 - - name: Push production image (only if tests passed) - if: success() - uses: docker/build-push-action@v6 - with: - context: . - push: true - file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - tags: | - harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} - harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:latest +# - name: Read version from file +# id: vars +# run: | +# VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") +# echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV +# cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/trigger_noconda.py Images/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . +# cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . +# cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . + +# - name: Make tinqiita targets +# # second copy of "qiita_server_certificates" is necessary to match path for docker build, first copy for mounting into container +# run: | +# make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./references/qp-target-gene ./environments/qiita_db.env ./environments/qiita.env config +# cp -r ./references/qiita_server_certificates ./qiita_server_certificates + +# - name: Build Image (but do not push yet) +# uses: docker/build-push-action@v6 +# with: +# context: . +# push: false +# load: true +# file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile +# tags: tinqiita/${{ matrix.plugin }}:testcandidate + +# - name: debug docker +# run: | +# docker image ls -a +# docker ps -a + +# - name: adapt compose file to select specific plugin +# run: | +# sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml +# sed -i "s|image: janssenlab/${{ matrix.plugin }}:latest|image: tinqiita/${{ matrix.plugin }}:testcandidate|" compose_github.yaml + +# - name: Run docker compose +# if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} +# uses: hoverkraft-tech/compose-action@v2.0.1 +# with: +# compose-file: "compose_github.yaml" +# services: | +# nginx +# - name: Execute tests in the running services (wait till qiita plugins are registered) +# if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} +# run: | +# sleep 5 +# docker compose exec qiita /bin/bash -c "cat /logs/*; cat /qiita_plugins/*" +# docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_plugin.sh" + +# - name: Push production image (only if tests passed) +# if: success() +# uses: docker/build-push-action@v6 +# with: +# context: . +# push: true +# file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile +# tags: | +# harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} +# harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:latest From 6d94ac72b46619634a396584bc0c53800d3979fa Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 16:52:59 +0200 Subject: [PATCH 261/287] two phases --- .github/workflows/buildContainer.yaml | 63 ++++++++++++++++++++++----- compose_github.yaml | 10 ++--- 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index f047057..04b6f44 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -27,12 +27,10 @@ jobs: cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . - - name: Create certificate and fake reference databases + - name: Create certificate # second copy of "qiita_server_certificates" is necessary to match path for docker build, first copy for mounting into container run: | make ./references/qiita_server_certificates ./environments/qiita_db.env ./environments/qiita.env config - mkdir -p ./references/qp-deblur/ ./references/qp-target-gene - for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done cp -r ./references/qiita_server_certificates ./qiita_server_certificates - name: Log in to GitHub Container Registry @@ -42,7 +40,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build main qiita Images and push to github's own registry + - name: Build main qiita images and push to github's own registry uses: docker/build-push-action@v6 with: context: . @@ -51,13 +49,56 @@ jobs: file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate -# build_plugins: -# needs: build_main -# strategy: -# matrix: -# container: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder"] -# runs-on: ubuntu-latest -# steps: + build_plugins: + needs: build_main + strategy: + matrix: + plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder"] + runs-on: ubuntu-latest + steps: + - name: Checkout tinqiita repo + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Read image version from dockerfile + id: vars + run: | + VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt . + + - name: Create fake reference databases + run: | + mkdir -p ./references/qp-deblur/ ./references/qp-target-gene + for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done + + - name: Build plugin images + uses: docker/build-push-action@v6 + with: + context: . + push: false + load: true + file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + + - name: adapt compose file to select specific plugin + run: | + sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml + + - name: Run docker compose + uses: hoverkraft-tech/compose-action@v2.0.1 + with: + compose-file: "compose_github.yaml" + services: | + nginx + + - name: Execute tests in the running services + run: | + sleep 5 + docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" + + # jobs: # docker: diff --git a/compose_github.yaml b/compose_github.yaml index ddb6791..0767e7b 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -27,7 +27,7 @@ services: # start_period: 20s qiita-initialize-db: - image: harbor.computational.bio.uni-giessen.de/tinqiita/qiita:latest + image: ghcr.io/qiita-keycloak/qiita:testcandidate command: ['/start_qiita-initDB.sh'] depends_on: - qiita-db @@ -46,7 +46,7 @@ services: - qiita-net qiita: - image: harbor.computational.bio.uni-giessen.de/tinqiita/qiita:latest + image: ghcr.io/qiita-keycloak/qiita:testcandidate build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -82,7 +82,7 @@ services: - "21174:21174" qiita-worker: - image: harbor.computational.bio.uni-giessen.de/tinqiita/qiita:latest + image: ghcr.io/qiita-keycloak/qiita:testcandidate build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -142,7 +142,7 @@ services: # start_period: 20s nginx: - image: harbor.computational.bio.uni-giessen.de/tinqiita/nginx:latest + image: ghcr.io/qiita-keycloak/nginx:testcandidate build: context: ./Images/nginx dockerfile: Dockerfile @@ -306,7 +306,7 @@ services: plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume - image: harbor.computational.bio.uni-giessen.de/tinqiita/plugin_collector:latest + image: ghcr.io/qiita-keycloak/plugin_collector:testcandidate restart: no networks: - qiita-net From 6a6d81409ca38fa3515f62f3d08ff344bafe35ff Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 17:03:20 +0200 Subject: [PATCH 262/287] up/download certificates between jobs --- .github/workflows/buildContainer.yaml | 25 ++++++++++++++++++- .../plugin_collector.dockerfile | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 04b6f44..9720957 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -33,6 +33,12 @@ jobs: make ./references/qiita_server_certificates ./environments/qiita_db.env ./environments/qiita.env config cp -r ./references/qiita_server_certificates ./qiita_server_certificates + - name: Store certifactes for follow up jobs + uses: actions/upload-artifact@v4 + with: + name: certificates + path: ./references/qiita_server_certificates ./qiita_server_certificates + - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: @@ -44,10 +50,11 @@ jobs: uses: docker/build-push-action@v6 with: context: . - push: false load: true file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate + cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max build_plugins: needs: build_main @@ -69,6 +76,11 @@ jobs: echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt . + - name: Download certificates from job build_main + uses: actions/download-artifact@v4 + with: + name: certificates + - name: Create fake reference databases run: | mkdir -p ./references/qp-deblur/ ./references/qp-target-gene @@ -98,6 +110,17 @@ jobs: sleep 5 docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" + - name: Push production image (only if tests passed) + if: success() + uses: docker/build-push-action@v6 + with: + context: . + push: true + file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + tags: | + tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max # jobs: diff --git a/Images/plugin_collector/plugin_collector.dockerfile b/Images/plugin_collector/plugin_collector.dockerfile index 799da21..452c5b0 100644 --- a/Images/plugin_collector/plugin_collector.dockerfile +++ b/Images/plugin_collector/plugin_collector.dockerfile @@ -14,4 +14,4 @@ COPY fix_test_db.py /fix_test_db.py COPY start_plugin_collector.sh /start_plugin_collector.sh RUN chmod u+x /start_plugin_collector.sh -CMD /start_plugin_collector.sh \ No newline at end of file +CMD ["/start_plugin_collector.sh"] From 161c30644b1838b603a2f6a80039b98bdba609ea Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 17:04:46 +0200 Subject: [PATCH 263/287] login to ghcr --- .github/workflows/buildContainer.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 9720957..e29aa12 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -86,6 +86,13 @@ jobs: mkdir -p ./references/qp-deblur/ ./references/qp-target-gene for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build plugin images uses: docker/build-push-action@v6 with: From d87b55e57d2a6e8b6851bab04227bc6fde11e107 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 17:09:45 +0200 Subject: [PATCH 264/287] adding phase3: publish images --- .github/workflows/buildContainer.yaml | 112 ++++++++------------------ 1 file changed, 32 insertions(+), 80 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index e29aa12..68f202d 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -129,84 +129,36 @@ jobs: cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + publish_images: + needs: build_plugins + strategy: + matrix: + images: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", + "nginx", "qiita", "plugin_collector"] + runs-on: ubuntu-latest + steps: + - name: Checkout tinqiita repo + uses: actions/checkout@v4 -# jobs: -# docker: -# strategy: -# matrix: -# plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", -# "nginx", "qiita", "plugin_collector" -# ] -# runs-on: ubuntu-latest -# steps: -# - name: Checkout repository -# uses: actions/checkout@v4 - -# - name: Login to DockerHub -# uses: docker/login-action@v3 -# with: -# registry: harbor.computational.bio.uni-giessen.de -# username: ${{ vars.HARBOR_CB_USERNAME }} -# password: ${{ secrets.HARBOR_CB_SECRET }} - -# - name: Set up Docker Buildx -# uses: docker/setup-buildx-action@v3 - -# - name: Read version from file -# id: vars -# run: | -# VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") -# echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV -# cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/trigger_noconda.py Images/trigger.py Images/nginx/nginx_qiita.conf Images/${{ matrix.plugin }}/requirements.txt . -# cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . -# cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . - -# - name: Make tinqiita targets -# # second copy of "qiita_server_certificates" is necessary to match path for docker build, first copy for mounting into container -# run: | -# make ./references/qiita_server_certificates ./references/qp-deblur/reference-gg-raxml-bl.tre ./references/qp-target-gene ./environments/qiita_db.env ./environments/qiita.env config -# cp -r ./references/qiita_server_certificates ./qiita_server_certificates - -# - name: Build Image (but do not push yet) -# uses: docker/build-push-action@v6 -# with: -# context: . -# push: false -# load: true -# file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile -# tags: tinqiita/${{ matrix.plugin }}:testcandidate - -# - name: debug docker -# run: | -# docker image ls -a -# docker ps -a - -# - name: adapt compose file to select specific plugin -# run: | -# sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml -# sed -i "s|image: janssenlab/${{ matrix.plugin }}:latest|image: tinqiita/${{ matrix.plugin }}:testcandidate|" compose_github.yaml - -# - name: Run docker compose -# if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} -# uses: hoverkraft-tech/compose-action@v2.0.1 -# with: -# compose-file: "compose_github.yaml" -# services: | -# nginx -# - name: Execute tests in the running services (wait till qiita plugins are registered) -# if: ${{ !contains('nginx,qiita,plugin_collector', matrix.plugin) }} -# run: | -# sleep 5 -# docker compose exec qiita /bin/bash -c "cat /logs/*; cat /qiita_plugins/*" -# docker compose exec ${{ matrix.plugin }} /bin/bash -c "PLUGIN=${{ matrix.plugin }} bash /test_plugin.sh" - -# - name: Push production image (only if tests passed) -# if: success() -# uses: docker/build-push-action@v6 -# with: -# context: . -# push: true -# file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile -# tags: | -# harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:${{ env.IMAGE_TAG }} -# harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.plugin }}:latest + - name: Login to computational.bio registry + uses: docker/login-action@v3 + with: + registry: harbor.computational.bio.uni-giessen.de + username: ${{ vars.HARBOR_CB_USERNAME }} + password: ${{ secrets.HARBOR_CB_SECRET }} + + - name: Read image version from dockerfile + id: vars + run: | + VERSION=$(head -n 1 Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + + - name: Push production image + uses: docker/build-push-action@v6 + with: + context: . + push: true + file: Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile + tags: | + harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} + harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:latest From 504220c6caa8f89936701bf32e95f97f9fc2b119 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 17:15:20 +0200 Subject: [PATCH 265/287] transfer single dir --- .github/workflows/buildContainer.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 68f202d..d0b4d36 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -37,7 +37,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: certificates - path: ./references/qiita_server_certificates ./qiita_server_certificates + path: ./qiita_server_certificates - name: Log in to GitHub Container Registry uses: docker/login-action@v3 @@ -80,9 +80,11 @@ jobs: uses: actions/download-artifact@v4 with: name: certificates + path: ./qiita_server_certificates - name: Create fake reference databases run: | + cp -r ./references/qiita_server_certificates ./qiita_server_certificates mkdir -p ./references/qp-deblur/ ./references/qp-target-gene for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done From 8b3992c08f87761888a294751e4cad085f516af3 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 17:17:55 +0200 Subject: [PATCH 266/287] only store artefact in one of matrix jobs --- .github/workflows/buildContainer.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index d0b4d36..2353425 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -34,6 +34,7 @@ jobs: cp -r ./references/qiita_server_certificates ./qiita_server_certificates - name: Store certifactes for follow up jobs + if: ${{ matrix.container == 'nginx' }} uses: actions/upload-artifact@v4 with: name: certificates From 57d73ea7fb0bfc42e83fa6f5f0acb0bb2729cd9b Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 20:34:40 +0200 Subject: [PATCH 267/287] just certificates --- .github/workflows/buildContainer.yaml | 297 +++++++++++++------------- 1 file changed, 154 insertions(+), 143 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 2353425..bbd3565 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -1,3 +1,5 @@ +# todo: "make" files once and push around through artifacts! + name: docker on: @@ -6,27 +8,12 @@ on: - 'restructure_github_actions' jobs: - build_main: - strategy: - matrix: - container: ["nginx", "qiita", "plugin_collector"] + make_certificates: runs-on: ubuntu-latest steps: - name: Checkout tinqiita repo uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Read image version from dockerfile - id: vars - run: | - VERSION=$(head -n 1 Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile | cut -d ":" -f 2- | tr -d " ") - echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.container }}/start_${{ matrix.container }}.sh Images/test_plugin.sh Images/nginx/nginx_qiita.conf Images/${{ matrix.container }}/requirements.txt . - cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . - cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . - - name: Create certificate # second copy of "qiita_server_certificates" is necessary to match path for docker build, first copy for mounting into container run: | @@ -34,134 +21,158 @@ jobs: cp -r ./references/qiita_server_certificates ./qiita_server_certificates - name: Store certifactes for follow up jobs - if: ${{ matrix.container == 'nginx' }} uses: actions/upload-artifact@v4 with: name: certificates - path: ./qiita_server_certificates - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build main qiita images and push to github's own registry - uses: docker/build-push-action@v6 - with: - context: . - load: true - file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile - tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate - cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} - cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + path: | + ./qiita_server_certificates + ./references/qiita_server_certificates + + # build_main: + # needs: make_certificates + # strategy: + # matrix: + # container: ["nginx", "qiita", "plugin_collector"] + # runs-on: ubuntu-latest + # steps: + # - name: Checkout tinqiita repo + # uses: actions/checkout@v4 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v3 + + # - name: Read image version from dockerfile + # id: vars + # run: | + # VERSION=$(head -n 1 Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + # cp Images/${{ matrix.container }}/start_${{ matrix.container }}.sh Images/test_plugin.sh Images/nginx/nginx_qiita.conf Images/${{ matrix.container }}/requirements.txt . + # cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . + # cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . + + + # - name: Log in to GitHub Container Registry + # uses: docker/login-action@v3 + # with: + # registry: ghcr.io + # username: ${{ github.actor }} + # password: ${{ secrets.GITHUB_TOKEN }} + + # - name: Build main qiita images and push to github's own registry + # uses: docker/build-push-action@v6 + # with: + # context: . + # load: true + # file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile + # tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate + # cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + # cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max - build_plugins: - needs: build_main - strategy: - matrix: - plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder"] - runs-on: ubuntu-latest - steps: - - name: Checkout tinqiita repo - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Read image version from dockerfile - id: vars - run: | - VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") - echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt . - - - name: Download certificates from job build_main - uses: actions/download-artifact@v4 - with: - name: certificates - path: ./qiita_server_certificates - - - name: Create fake reference databases - run: | - cp -r ./references/qiita_server_certificates ./qiita_server_certificates - mkdir -p ./references/qp-deblur/ ./references/qp-target-gene - for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build plugin images - uses: docker/build-push-action@v6 - with: - context: . - push: false - load: true - file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - - - name: adapt compose file to select specific plugin - run: | - sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml - - - name: Run docker compose - uses: hoverkraft-tech/compose-action@v2.0.1 - with: - compose-file: "compose_github.yaml" - services: | - nginx - - - name: Execute tests in the running services - run: | - sleep 5 - docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" - - - name: Push production image (only if tests passed) - if: success() - uses: docker/build-push-action@v6 - with: - context: . - push: true - file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - tags: | - tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate - cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} - cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max - - publish_images: - needs: build_plugins - strategy: - matrix: - images: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", - "nginx", "qiita", "plugin_collector"] - runs-on: ubuntu-latest - steps: - - name: Checkout tinqiita repo - uses: actions/checkout@v4 - - - name: Login to computational.bio registry - uses: docker/login-action@v3 - with: - registry: harbor.computational.bio.uni-giessen.de - username: ${{ vars.HARBOR_CB_USERNAME }} - password: ${{ secrets.HARBOR_CB_SECRET }} - - - name: Read image version from dockerfile - id: vars - run: | - VERSION=$(head -n 1 Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile | cut -d ":" -f 2- | tr -d " ") - echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - - - name: Push production image - uses: docker/build-push-action@v6 - with: - context: . - push: true - file: Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile - tags: | - harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} - harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:latest + # build_plugins: + # needs: build_main + # strategy: + # matrix: + # plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder"] + # runs-on: ubuntu-latest + # steps: + # - name: Checkout tinqiita repo + # uses: actions/checkout@v4 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v3 + + # - name: Read image version from dockerfile + # id: vars + # run: | + # VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + # cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt . + + # - name: Download certificates from job build_main + # uses: actions/download-artifact@v4 + # with: + # name: certificates + # path: ./qiita_server_certificates + + # - name: Create fake reference databases + # run: | + # cp -r ./references/qiita_server_certificates ./qiita_server_certificates + # mkdir -p ./references/qp-deblur/ ./references/qp-target-gene + # for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done + + # - name: Log in to GitHub Container Registry + # uses: docker/login-action@v3 + # with: + # registry: ghcr.io + # username: ${{ github.actor }} + # password: ${{ secrets.GITHUB_TOKEN }} + + # - name: Build plugin images + # uses: docker/build-push-action@v6 + # with: + # context: . + # push: false + # load: true + # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + + # - name: adapt compose file to select specific plugin + # run: | + # sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml + + # - name: Run docker compose + # uses: hoverkraft-tech/compose-action@v2.0.1 + # with: + # compose-file: "compose_github.yaml" + # services: | + # nginx + + # - name: Execute tests in the running services + # run: | + # sleep 5 + # docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" + + # - name: Push production image (only if tests passed) + # if: success() + # uses: docker/build-push-action@v6 + # with: + # context: . + # push: true + # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + # tags: | + # tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + # cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + # cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + + # publish_images: + # needs: build_plugins + # strategy: + # matrix: + # images: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", + # "nginx", "qiita", "plugin_collector"] + # runs-on: ubuntu-latest + # steps: + # - name: Checkout tinqiita repo + # uses: actions/checkout@v4 + + # - name: Login to computational.bio registry + # uses: docker/login-action@v3 + # with: + # registry: harbor.computational.bio.uni-giessen.de + # username: ${{ vars.HARBOR_CB_USERNAME }} + # password: ${{ secrets.HARBOR_CB_SECRET }} + + # - name: Read image version from dockerfile + # id: vars + # run: | + # VERSION=$(head -n 1 Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + + # - name: Push production image + # uses: docker/build-push-action@v6 + # with: + # context: . + # push: true + # file: Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile + # tags: | + # harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} + # harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:latest From dec95fa2ad84c4801bef1b703a1a53272d0f1109 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 20:37:51 +0200 Subject: [PATCH 268/287] now add build main image phase --- .github/workflows/buildContainer.yaml | 75 ++++++++++++++------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index bbd3565..c958107 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -28,45 +28,50 @@ jobs: ./qiita_server_certificates ./references/qiita_server_certificates - # build_main: - # needs: make_certificates - # strategy: - # matrix: - # container: ["nginx", "qiita", "plugin_collector"] - # runs-on: ubuntu-latest - # steps: - # - name: Checkout tinqiita repo - # uses: actions/checkout@v4 - - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v3 + build_main: + needs: make_certificates + strategy: + matrix: + container: ["nginx", "qiita", "plugin_collector"] + runs-on: ubuntu-latest + steps: + - name: Checkout tinqiita repo + uses: actions/checkout@v4 - # - name: Read image version from dockerfile - # id: vars - # run: | - # VERSION=$(head -n 1 Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile | cut -d ":" -f 2- | tr -d " ") - # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - # cp Images/${{ matrix.container }}/start_${{ matrix.container }}.sh Images/test_plugin.sh Images/nginx/nginx_qiita.conf Images/${{ matrix.container }}/requirements.txt . - # cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . - # cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Read image version from dockerfile + id: vars + run: | + VERSION=$(head -n 1 Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + cp Images/${{ matrix.container }}/start_${{ matrix.container }}.sh Images/test_plugin.sh Images/nginx/nginx_qiita.conf Images/${{ matrix.container }}/requirements.txt . + cp Images/qiita/config_portal.cfg Images/qiita/config_qiita_oidc.cfg Images/qiita/drop_workflows.py Images/qiita/start_plugin.py Images/qiita/start_qiita-initDB.sh Images/qiita/start_qiita.sh . + cp Images/plugin_collector/collect_configs.py Images/plugin_collector/fix_test_db.py Images/plugin_collector/stefan_cert.conf Images/plugin_collector/stefan_csr.conf . + + - name: Download certificates from job build_main + uses: actions/download-artifact@v4 + with: + name: certificates + path: ./ - # - name: Log in to GitHub Container Registry - # uses: docker/login-action@v3 - # with: - # registry: ghcr.io - # username: ${{ github.actor }} - # password: ${{ secrets.GITHUB_TOKEN }} + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - # - name: Build main qiita images and push to github's own registry - # uses: docker/build-push-action@v6 - # with: - # context: . - # load: true - # file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile - # tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate - # cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} - # cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + - name: Build main qiita images and push to github's own registry + uses: docker/build-push-action@v6 + with: + context: . + load: true + file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile + tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate + cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max # build_plugins: # needs: build_main From 85e394b02afb25a63de571aff3b9be6bbca2e732 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 20:47:21 +0200 Subject: [PATCH 269/287] add plugin build --- .github/workflows/buildContainer.yaml | 151 +++++++++++++++----------- 1 file changed, 86 insertions(+), 65 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index c958107..0c796ee 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -72,81 +72,102 @@ jobs: tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max - - # build_plugins: - # needs: build_main - # strategy: - # matrix: - # plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder"] - # runs-on: ubuntu-latest - # steps: - # - name: Checkout tinqiita repo - # uses: actions/checkout@v4 - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v3 + make_references: + needs: build_main + runs-on: ubuntu-latest + steps: + - name: Checkout tinqiita repo + uses: actions/checkout@v4 - # - name: Read image version from dockerfile - # id: vars - # run: | - # VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") - # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - # cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt . + - name: Create fake reference databases + run: | + mkdir -p ./references/qp-deblur/ ./references/qp-target-gene + for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done - # - name: Download certificates from job build_main - # uses: actions/download-artifact@v4 - # with: - # name: certificates - # path: ./qiita_server_certificates + - name: Store fake references for follow up jobs + uses: actions/upload-artifact@v4 + with: + name: fake_references + path: | + ./references/qp-deblur + ./references/qp-target-gene - # - name: Create fake reference databases - # run: | - # cp -r ./references/qiita_server_certificates ./qiita_server_certificates - # mkdir -p ./references/qp-deblur/ ./references/qp-target-gene - # for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done + build_plugins: + needs: + - build_main + - make_references + strategy: + matrix: + plugin: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder"] + runs-on: ubuntu-latest + steps: + - name: Checkout tinqiita repo + uses: actions/checkout@v4 - # - name: Log in to GitHub Container Registry - # uses: docker/login-action@v3 - # with: - # registry: ghcr.io - # username: ${{ github.actor }} - # password: ${{ secrets.GITHUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - # - name: Build plugin images - # uses: docker/build-push-action@v6 - # with: - # context: . - # push: false - # load: true - # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + - name: Read image version from dockerfile + id: vars + run: | + VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt . - # - name: adapt compose file to select specific plugin - # run: | - # sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml + - name: Download certificates from job build_main + uses: actions/download-artifact@v4 + with: + name: certificates + path: ./ + - name: Download fake references + uses: actions/download-artifact@v4 + with: + name: fake_references + path: ./ - # - name: Run docker compose - # uses: hoverkraft-tech/compose-action@v2.0.1 - # with: - # compose-file: "compose_github.yaml" - # services: | - # nginx + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - # - name: Execute tests in the running services - # run: | - # sleep 5 - # docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" + - name: Build plugin images + uses: docker/build-push-action@v6 + with: + context: . + push: false + load: true + file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - # - name: Push production image (only if tests passed) - # if: success() - # uses: docker/build-push-action@v6 - # with: - # context: . - # push: true - # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - # tags: | - # tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate - # cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} - # cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + - name: adapt compose file to select specific plugin + run: | + sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml + + - name: Run docker compose + uses: hoverkraft-tech/compose-action@v2.0.1 + with: + compose-file: "compose_github.yaml" + services: | + nginx + + - name: Execute tests in the running services + run: | + sleep 5 + docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" + + - name: Push production image (only if tests passed) + if: success() + uses: docker/build-push-action@v6 + with: + context: . + push: true + file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + tags: | + tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max # publish_images: # needs: build_plugins From d70700690a57e12daf0eae888a01a7cc66dcc4b4 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 20:59:02 +0200 Subject: [PATCH 270/287] copy missing files --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 0c796ee..f296909 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -113,7 +113,7 @@ jobs: run: | VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt . + cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt Images/trigger_noconda.py Images/trigger.py . - name: Download certificates from job build_main uses: actions/download-artifact@v4 From 96784464550e0b989a09d2c27b2cb0029adfcf4d Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 21:05:34 +0200 Subject: [PATCH 271/287] add env configuration files --- .github/workflows/buildContainer.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index f296909..510eca3 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -82,6 +82,7 @@ jobs: - name: Create fake reference databases run: | + make ./environments/qiita_db.env ./environments/qiita.env config mkdir -p ./references/qp-deblur/ ./references/qp-target-gene for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done @@ -92,6 +93,7 @@ jobs: path: | ./references/qp-deblur ./references/qp-target-gene + ./environments build_plugins: needs: From 33bb56621866a71a4b4781203d25175cb7286875 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 21:17:38 +0200 Subject: [PATCH 272/287] pull from ghcr --- compose_github.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compose_github.yaml b/compose_github.yaml index 0767e7b..b2dde1e 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -170,7 +170,7 @@ services: # start_period: 10s qtp-biom: - image: tinqiita/qtp-biom:testcandidate + image: ghcr.io/qiita-keycloak/qtp-biom:testcandidate command: ['./start_qtp-biom.sh'] # network_mode: host # stdin_open: true @@ -186,7 +186,7 @@ services: - qiita-net qtp-sequencing: - image: tinqiita/qtp-sequencing:testcandidate + image: ghcr.io/qiita-keycloak/qtp-sequencing:testcandidate command: ['./start_qtp-sequencing.sh'] # network_mode: host # stdin_open: true @@ -208,7 +208,7 @@ services: # start_period: 3s qp-target-gene: - image: tinqiita/qp-target-gene:testcandidate + image: ghcr.io/qiita-keycloak/qp-target-gene:testcandidate command: ['./start_qp-target-gene.sh'] # network_mode: host # stdin_open: true @@ -225,7 +225,7 @@ services: - qiita-net qtp-visualization: - image: tinqiita/qtp-visualization:testcandidate + image: ghcr.io/qiita-keycloak/qtp-visualization:testcandidate command: ['./start_qtp-visualization.sh'] # network_mode: host # stdin_open: true @@ -241,7 +241,7 @@ services: - qiita-net qtp-diversity: - image: tinqiita/qtp-diversity:testcandidate + image: ghcr.io/qiita-keycloak/qtp-diversity:testcandidate command: ['./start_qtp-diversity.sh'] # network_mode: host # stdin_open: true @@ -257,7 +257,7 @@ services: - qiita-net qp-deblur: - image: tinqiita/qp-deblur:testcandidate + image: ghcr.io/qiita-keycloak/qp-deblur:testcandidate command: ['./start_qp-deblur.sh'] restart: no volumes: @@ -271,7 +271,7 @@ services: - qiita-net qp-qiime2: - image: tinqiita/qp-qiime2:testcandidate + image: ghcr.io/qiita-keycloak/qp-qiime2:testcandidate command: ['./start_qp-qiime2.sh'] # network_mode: host # stdin_open: true @@ -288,7 +288,7 @@ services: - qiita-net qtp-job-output-folder: - image: tinqiita/qtp-job-output-folder:testcandidate + image: ghcr.io/qiita-keycloak/qtp-job-output-folder:testcandidate command: ['./start_qtp-job-output-folder.sh'] # network_mode: host # stdin_open: true From d672d22f159fe39c1072c0c6fec23de0f67504f8 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 21:33:49 +0200 Subject: [PATCH 273/287] push to ghcr --- .github/workflows/buildContainer.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 510eca3..753ccc1 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -139,9 +139,11 @@ jobs: uses: docker/build-push-action@v6 with: context: . - push: false load: true file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + tags: tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max - name: adapt compose file to select specific plugin run: | From 8233831ffe0d34789e94057b8679b0ceef265dd3 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 21:34:29 +0200 Subject: [PATCH 274/287] fix yaml --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 753ccc1..8e9616a 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -141,7 +141,7 @@ jobs: context: . load: true file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - tags: tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max From 0bdeb4d93925296e66a6c44c00732eeed1791bb7 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 21:49:28 +0200 Subject: [PATCH 275/287] adding jlab/ --- compose_github.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/compose_github.yaml b/compose_github.yaml index b2dde1e..443a6f9 100644 --- a/compose_github.yaml +++ b/compose_github.yaml @@ -27,7 +27,7 @@ services: # start_period: 20s qiita-initialize-db: - image: ghcr.io/qiita-keycloak/qiita:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qiita:testcandidate command: ['/start_qiita-initDB.sh'] depends_on: - qiita-db @@ -46,7 +46,7 @@ services: - qiita-net qiita: - image: ghcr.io/qiita-keycloak/qiita:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qiita:testcandidate build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -82,7 +82,7 @@ services: - "21174:21174" qiita-worker: - image: ghcr.io/qiita-keycloak/qiita:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qiita:testcandidate build: # image wird hier direkt gebaut context: ./Images/qiita dockerfile: Dockerfile @@ -142,7 +142,7 @@ services: # start_period: 20s nginx: - image: ghcr.io/qiita-keycloak/nginx:testcandidate + image: ghcr.io/jlab/qiita-keycloak/nginx:testcandidate build: context: ./Images/nginx dockerfile: Dockerfile @@ -170,7 +170,7 @@ services: # start_period: 10s qtp-biom: - image: ghcr.io/qiita-keycloak/qtp-biom:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qtp-biom:testcandidate command: ['./start_qtp-biom.sh'] # network_mode: host # stdin_open: true @@ -186,7 +186,7 @@ services: - qiita-net qtp-sequencing: - image: ghcr.io/qiita-keycloak/qtp-sequencing:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qtp-sequencing:testcandidate command: ['./start_qtp-sequencing.sh'] # network_mode: host # stdin_open: true @@ -208,7 +208,7 @@ services: # start_period: 3s qp-target-gene: - image: ghcr.io/qiita-keycloak/qp-target-gene:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qp-target-gene:testcandidate command: ['./start_qp-target-gene.sh'] # network_mode: host # stdin_open: true @@ -225,7 +225,7 @@ services: - qiita-net qtp-visualization: - image: ghcr.io/qiita-keycloak/qtp-visualization:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qtp-visualization:testcandidate command: ['./start_qtp-visualization.sh'] # network_mode: host # stdin_open: true @@ -241,7 +241,7 @@ services: - qiita-net qtp-diversity: - image: ghcr.io/qiita-keycloak/qtp-diversity:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qtp-diversity:testcandidate command: ['./start_qtp-diversity.sh'] # network_mode: host # stdin_open: true @@ -257,7 +257,7 @@ services: - qiita-net qp-deblur: - image: ghcr.io/qiita-keycloak/qp-deblur:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qp-deblur:testcandidate command: ['./start_qp-deblur.sh'] restart: no volumes: @@ -271,7 +271,7 @@ services: - qiita-net qp-qiime2: - image: ghcr.io/qiita-keycloak/qp-qiime2:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qp-qiime2:testcandidate command: ['./start_qp-qiime2.sh'] # network_mode: host # stdin_open: true @@ -288,7 +288,7 @@ services: - qiita-net qtp-job-output-folder: - image: ghcr.io/qiita-keycloak/qtp-job-output-folder:testcandidate + image: ghcr.io/jlab/qiita-keycloak/qtp-job-output-folder:testcandidate command: ['./start_qtp-job-output-folder.sh'] # network_mode: host # stdin_open: true @@ -306,7 +306,7 @@ services: plugin-collector: # prior to qiita (master and worker) start up, iterates through the QIITA_PLUGINS : separated list of plugin containers # to compile all q*.conf files from plugin containers in the server-plugin-configs volume - image: ghcr.io/qiita-keycloak/plugin_collector:testcandidate + image: ghcr.io/jlab/qiita-keycloak/plugin_collector:testcandidate restart: no networks: - qiita-net From 2921b2f462bb84fe91d87b96e78086065f5aac85 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 22:04:08 +0200 Subject: [PATCH 276/287] push to ghcr --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 8e9616a..7158435 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -67,7 +67,7 @@ jobs: uses: docker/build-push-action@v6 with: context: . - load: true + push: true file: Images/${{ matrix.container }}/${{ matrix.container }}.dockerfile tags: ghcr.io/${{ github.repository }}/${{ matrix.container }}:testcandidate cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} From d1a1b038c974ca4bba422818307e5a5ea7cca3fa Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 22:18:20 +0200 Subject: [PATCH 277/287] fix tag syntax --- .github/workflows/buildContainer.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 7158435..55e54a9 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -168,10 +168,7 @@ jobs: context: . push: true file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - tags: | - tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate - cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} - cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate # publish_images: # needs: build_plugins From d346019991ea321eeeb8da656be83ffa63f86474 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Thu, 11 Sep 2025 23:07:50 +0200 Subject: [PATCH 278/287] create real SEPP references for qp-deblur & push to habor --- .github/workflows/buildContainer.yaml | 83 +++++++++++++++------------ 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 55e54a9..cdaefc2 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -80,11 +80,11 @@ jobs: - name: Checkout tinqiita repo uses: actions/checkout@v4 - - name: Create fake reference databases + - name: Create partially fake reference databases run: | - make ./environments/qiita_db.env ./environments/qiita.env config mkdir -p ./references/qp-deblur/ ./references/qp-target-gene - for f in `echo "./references/qp-deblur/reference-gg-raxml-bl.tre references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done + make ./environments/qiita_db.env ./environments/qiita.env config ./references/qp-deblur/reference-gg-raxml-bl.tre + for f in `echo "references/qp-target-gene/97_otus.fasta references/qp-target-gene/97_otus.tree references/qp-target-gene/97_otu_taxonomy.txt"`; do echo "fake" > $f; done - name: Store fake references for follow up jobs uses: actions/upload-artifact@v4 @@ -161,7 +161,7 @@ jobs: sleep 5 docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" - - name: Push production image (only if tests passed) + - name: Push image to ghcr (only if tests passed) if: success() uses: docker/build-push-action@v6 with: @@ -170,36 +170,45 @@ jobs: file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate - # publish_images: - # needs: build_plugins - # strategy: - # matrix: - # images: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", - # "nginx", "qiita", "plugin_collector"] - # runs-on: ubuntu-latest - # steps: - # - name: Checkout tinqiita repo - # uses: actions/checkout@v4 - - # - name: Login to computational.bio registry - # uses: docker/login-action@v3 - # with: - # registry: harbor.computational.bio.uni-giessen.de - # username: ${{ vars.HARBOR_CB_USERNAME }} - # password: ${{ secrets.HARBOR_CB_SECRET }} - - # - name: Read image version from dockerfile - # id: vars - # run: | - # VERSION=$(head -n 1 Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile | cut -d ":" -f 2- | tr -d " ") - # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - - # - name: Push production image - # uses: docker/build-push-action@v6 - # with: - # context: . - # push: true - # file: Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile - # tags: | - # harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} - # harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:latest + publish_images: + needs: + - build_plugins + - build_main + strategy: + matrix: + images: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", + "nginx", "qiita", "plugin_collector"] + runs-on: ubuntu-latest + steps: + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to computational.bio registry + uses: docker/login-action@v3 + with: + registry: harbor.computational.bio.uni-giessen.de + username: ${{ vars.HARBOR_CB_USERNAME }} + password: ${{ secrets.HARBOR_CB_SECRET }} + + - name: Pull image from GHCR + run: docker pull ghcr.io/${{ github.repository }}/{{ matrix.images }}:testcandidate + + - name: Read image version from dockerfile + id: vars + run: | + VERSION=$(head -n 1 Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + + - name: Retag image for Docker Hub + run: docker tag \ + ghcr.io/${{ github.repository }}/${{ matrix.images }}:testcandidate \ + harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} + + - name: Push image to Docker Hub + run: | + docker push harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} + docker push harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:latest From 9ad6f15148edbbc8eadd6ee13dccafd3354c24f0 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 07:29:30 +0200 Subject: [PATCH 279/287] make it a variable --- .github/workflows/buildContainer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index cdaefc2..aec9d62 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -195,7 +195,7 @@ jobs: password: ${{ secrets.HARBOR_CB_SECRET }} - name: Pull image from GHCR - run: docker pull ghcr.io/${{ github.repository }}/{{ matrix.images }}:testcandidate + run: docker pull ghcr.io/${{ github.repository }}/${{ matrix.images }}:testcandidate - name: Read image version from dockerfile id: vars From 702e85f220114b839a76cc4f426047f7d4fca87a Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 08:39:58 +0200 Subject: [PATCH 280/287] checkout repo to obtain version number from docker file --- .github/workflows/buildContainer.yaml | 93 ++++++++++++++++++++++++--- Images/qp-qiime2/qp-qiime2.dockerfile | 2 + 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index aec9d62..19bcc2c 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -170,16 +170,94 @@ jobs: file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + # build_mulit_plugins: + # needs: + # - build_plugins + # strategy: + # matrix: + # plugin: ["qp-qiime2"] + # runs-on: ubuntu-latest + # steps: + # - name: Checkout tinqiita repo + # uses: actions/checkout@v4 + + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@v3 + + # - name: Read image version from dockerfile + # id: vars + # run: | + # VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + # cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt Images/trigger_noconda.py Images/trigger.py . + + # - name: Download certificates from job build_main + # uses: actions/download-artifact@v4 + # with: + # name: certificates + # path: ./ + # - name: Download fake references + # uses: actions/download-artifact@v4 + # with: + # name: fake_references + # path: ./ + + # - name: Log in to GitHub Container Registry + # uses: docker/login-action@v3 + # with: + # registry: ghcr.io + # username: ${{ github.actor }} + # password: ${{ secrets.GITHUB_TOKEN }} + + # - name: Build plugin images + # uses: docker/build-push-action@v6 + # with: + # context: . + # load: true + # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + # tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + # cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + # cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + + # - name: adapt compose file to select specific plugin + # run: | + # sed -i "s|||" compose_github.yaml + # sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml + + # - name: Run docker compose + # uses: hoverkraft-tech/compose-action@v2.0.1 + # with: + # compose-file: "compose_github.yaml" + # services: | + # nginx + + # - name: Execute tests in the running services + # run: | + # sleep 5 + # docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" + + # - name: Push image to ghcr (only if tests passed) + # if: success() + # uses: docker/build-push-action@v6 + # with: + # context: . + # push: true + # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile + # tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + publish_images: needs: - build_plugins - build_main strategy: matrix: - images: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", + image: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", "nginx", "qiita", "plugin_collector"] runs-on: ubuntu-latest steps: + - name: Checkout tinqiita repo + uses: actions/checkout@v4 + - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: @@ -195,20 +273,19 @@ jobs: password: ${{ secrets.HARBOR_CB_SECRET }} - name: Pull image from GHCR - run: docker pull ghcr.io/${{ github.repository }}/${{ matrix.images }}:testcandidate + run: docker pull ghcr.io/${{ github.repository }}/${{ matrix.image }}:testcandidate - name: Read image version from dockerfile id: vars run: | - VERSION=$(head -n 1 Images/${{ matrix.images }}/${{ matrix.images }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + VERSION=$(head -n 1 Images/${{ matrix.image }}/${{ matrix.image }}.dockerfile | cut -d ":" -f 2- | tr -d " ") echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - name: Retag image for Docker Hub - run: docker tag \ - ghcr.io/${{ github.repository }}/${{ matrix.images }}:testcandidate \ - harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} + run: | + docker tag ghcr.io/${{ github.repository }}/${{ matrix.image }}:testcandidate harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.image }}:${{ env.IMAGE_TAG }} - name: Push image to Docker Hub run: | - docker push harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:${{ env.IMAGE_TAG }} - docker push harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.images }}:latest + docker push harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.image }}:${{ env.IMAGE_TAG }} + docker push harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.image }}:latest diff --git a/Images/qp-qiime2/qp-qiime2.dockerfile b/Images/qp-qiime2/qp-qiime2.dockerfile index 6f63281..0cc7639 100644 --- a/Images/qp-qiime2/qp-qiime2.dockerfile +++ b/Images/qp-qiime2/qp-qiime2.dockerfile @@ -1,3 +1,5 @@ +# VERSION: 2025.09.12 + FROM ubuntu:24.04 ARG MINIFORGE_VERSION=24.1.2-0 From 84a43c1c58554b278a8e00e4347e433c30628e2f Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 08:56:42 +0200 Subject: [PATCH 281/287] add action for qp-qiime2 --- .github/workflows/buildContainer.yaml | 157 +++++++++++++------------- 1 file changed, 81 insertions(+), 76 deletions(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 19bcc2c..c1aa20d 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -3,9 +3,12 @@ name: docker on: + pull_request: + branches: + - tinqiita push: branches: - - 'restructure_github_actions' + - tinqiita jobs: make_certificates: @@ -170,89 +173,91 @@ jobs: file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate - # build_mulit_plugins: - # needs: - # - build_plugins - # strategy: - # matrix: - # plugin: ["qp-qiime2"] - # runs-on: ubuntu-latest - # steps: - # - name: Checkout tinqiita repo - # uses: actions/checkout@v4 - - # - name: Set up Docker Buildx - # uses: docker/setup-buildx-action@v3 - - # - name: Read image version from dockerfile - # id: vars - # run: | - # VERSION=$(head -n 1 Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") - # echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV - # cp Images/${{ matrix.plugin }}/start_${{ matrix.plugin }}.sh Images/test_plugin.sh Images/${{ matrix.plugin }}/requirements.txt Images/trigger_noconda.py Images/trigger.py . - - # - name: Download certificates from job build_main - # uses: actions/download-artifact@v4 - # with: - # name: certificates - # path: ./ - # - name: Download fake references - # uses: actions/download-artifact@v4 - # with: - # name: fake_references - # path: ./ - - # - name: Log in to GitHub Container Registry - # uses: docker/login-action@v3 - # with: - # registry: ghcr.io - # username: ${{ github.actor }} - # password: ${{ secrets.GITHUB_TOKEN }} - - # - name: Build plugin images - # uses: docker/build-push-action@v6 - # with: - # context: . - # load: true - # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - # tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate - # cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} - # cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max - - # - name: adapt compose file to select specific plugin - # run: | - # sed -i "s|||" compose_github.yaml - # sed -i "s/MATRIXPLUGIN/${{ matrix.plugin }}/g" compose_github.yaml - - # - name: Run docker compose - # uses: hoverkraft-tech/compose-action@v2.0.1 - # with: - # compose-file: "compose_github.yaml" - # services: | - # nginx - - # - name: Execute tests in the running services - # run: | - # sleep 5 - # docker compose exec ${{ matrix.plugin }} /bin/bash -c "bash /test_plugin.sh" - - # - name: Push image to ghcr (only if tests passed) - # if: success() - # uses: docker/build-push-action@v6 - # with: - # context: . - # push: true - # file: Images/${{ matrix.plugin }}/${{ matrix.plugin }}.dockerfile - # tags: ghcr.io/${{ github.repository }}/${{ matrix.plugin }}:testcandidate + # the qp-qiime2 plugin cannot be tested in isolation, it also needs qtp-diversity and qtp-visualization to be active in qiita + build_mulit_plugins: + needs: + - build_plugins + strategy: + matrix: + multiplugin: ["qp-qiime2"] + runs-on: ubuntu-latest + steps: + - name: Checkout tinqiita repo + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Read image version from dockerfile + id: vars + run: | + VERSION=$(head -n 1 Images/${{ matrix.multiplugin }}/${{ matrix.multiplugin }}.dockerfile | cut -d ":" -f 2- | tr -d " ") + echo "IMAGE_TAG=$VERSION" >> $GITHUB_ENV + cp Images/${{ matrix.multiplugin }}/start_${{ matrix.multiplugin }}.sh Images/test_plugin.sh Images/${{ matrix.multiplugin }}/requirements.txt Images/trigger_noconda.py Images/trigger.py . + + - name: Download certificates from job build_main + uses: actions/download-artifact@v4 + with: + name: certificates + path: ./ + - name: Download fake references + uses: actions/download-artifact@v4 + with: + name: fake_references + path: ./ + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build plugin images + uses: docker/build-push-action@v6 + with: + context: . + load: true + file: Images/${{ matrix.multiplugin }}/${{ matrix.multiplugin }}.dockerfile + tags: ghcr.io/${{ github.repository }}/${{ matrix.multiplugin }}:testcandidate + cache-from: type=gha,scope=tinqiita-${{ github.ref_name }} + cache-to: type=gha,scope=tinqiita-${{ github.ref_name }},mode=max + + - name: adapt compose file to select specific plugin + run: | + if [[ "${{ matrix.multiplugin }}" == "qp-qiime2" ]]; then sed -i 's|- QIITA_PLUGINS="MATRIXPLUGIN:"|- QIITA_PLUGINS="${{ matrix.multiplugin }}:qtp-diversity:qtp-visualization:"|' compose_github.yaml; sed -i 's|MATRIXPLUGIN:|${{ matrix.multiplugin }}:\n condition: service_started\n qtp-diversity:\n condition: service_started\n qtp-visualization:|' compose_github.yaml; fi; + + - name: Run docker compose + uses: hoverkraft-tech/compose-action@v2.0.1 + with: + compose-file: "compose_github.yaml" + services: | + nginx + + - name: Execute tests in the running services + run: | + sleep 5 + docker compose exec ${{ matrix.multiplugin }} /bin/bash -c "bash /test_plugin.sh" + + - name: Push image to ghcr (only if tests passed) + if: success() + uses: docker/build-push-action@v6 + with: + context: . + push: true + file: Images/${{ matrix.multiplugin }}/${{ matrix.multiplugin }}.dockerfile + tags: ghcr.io/${{ github.repository }}/${{ matrix.multiplugin }}:testcandidate publish_images: needs: - build_plugins - build_main + - build_mulit_plugins strategy: matrix: image: ["qp-deblur", "qtp-biom", "qtp-sequencing", "qtp-visualization", "qtp-diversity", "qp-target-gene", "qtp-job-output-folder", - "nginx", "qiita", "plugin_collector"] + "nginx", "qiita", "plugin_collector", + "qp-qiime2"] runs-on: ubuntu-latest steps: - name: Checkout tinqiita repo From 6a7f4c3cb50224035af2a9294c5bc76e3fbcf7c1 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 10:47:57 +0200 Subject: [PATCH 282/287] also create local "latest" tag before pushing --- .github/workflows/buildContainer.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 19bcc2c..7f7c79b 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -284,6 +284,7 @@ jobs: - name: Retag image for Docker Hub run: | docker tag ghcr.io/${{ github.repository }}/${{ matrix.image }}:testcandidate harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.image }}:${{ env.IMAGE_TAG }} + docker tag ghcr.io/${{ github.repository }}/${{ matrix.image }}:testcandidate harbor.computational.bio.uni-giessen.de/tinqiita/${{ matrix.image }}:latest - name: Push image to Docker Hub run: | From 12027b57b065c3f6be17dd6e36517abfe3a207c0 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 12:29:43 +0200 Subject: [PATCH 283/287] adding misisng file --- Images/qp-qiime2/requirements.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Images/qp-qiime2/requirements.txt diff --git a/Images/qp-qiime2/requirements.txt b/Images/qp-qiime2/requirements.txt new file mode 100644 index 0000000..4493267 --- /dev/null +++ b/Images/qp-qiime2/requirements.txt @@ -0,0 +1,9 @@ +tornado +q2-umap +q2-greengenes2 +certifi +pip-system-certs + +-e /qiita_client +-e /qiita-files +-e /qp-qiime2 From 26ee53688cd91207ccb7263c935532a0583c4786 Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 13:36:18 +0200 Subject: [PATCH 284/287] some some gigs of image size by cleaning up conda --- Images/qp-qiime2/qp-qiime2.dockerfile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Images/qp-qiime2/qp-qiime2.dockerfile b/Images/qp-qiime2/qp-qiime2.dockerfile index 0cc7639..499f542 100644 --- a/Images/qp-qiime2/qp-qiime2.dockerfile +++ b/Images/qp-qiime2/qp-qiime2.dockerfile @@ -28,14 +28,16 @@ RUN wget https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_ # install tornado based trigger layer in base environment RUN pip install -U pip -RUN conda install tornado +RUN pip install tornado COPY trigger.py /trigger.py # Download qiime2 yaml RUN wget --quiet https://data.qiime2.org/distro/core/qiime2-2023.5-py38-linux-conda.yml # Create conda env -RUN conda env create --name qiime2 -y --file qiime2-2023.5-py38-linux-conda.yml +RUN conda env create --name qiime2 -y --file qiime2-2023.5-py38-linux-conda.yml \ + && conda clean --all -y \ + && rm -rf /opt/conda/pkgs # Make RUN commands use the new environment: # append --format docker to the build command, see https://github.com/containers/podman/issues/8477 SHELL ["conda", "run", "-p", "/opt/conda/envs/qiime2", "/bin/bash", "-c"] @@ -61,8 +63,9 @@ RUN export QP_QIIME2_DBS=/databases # configuring the filtering QZAs available for QIIME 2 RUN mkdir /filtering -RUN wget -O /filtering/bloom-analyses.zip https://github.com/knightlab-analyses/bloom-analyses/archive/refs/heads/master.zip -RUN unzip -j /filtering/bloom-analyses.zip bloom-analyses-master/data/qiime2-artifacts-for-qiita/*.qza -d /filtering/ +RUN wget -O /filtering/bloom-analyses.zip https://github.com/knightlab-analyses/bloom-analyses/archive/refs/heads/master.zip \ + && unzip -j /filtering/bloom-analyses.zip bloom-analyses-master/data/qiime2-artifacts-for-qiita/*.qza -d /filtering/ \ + && rm -f /filtering/bloom-analyses.zip RUN export QP_QIIME2_FILTER_QZA=/filtering/ # TODO: should the plugin get the server configuration?! From bac91fa4997fad2265e438dceed0fb936ed8b5cd Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 14:29:18 +0200 Subject: [PATCH 285/287] activate conda env for qp-qiime2 --- Images/test_plugin.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Images/test_plugin.sh b/Images/test_plugin.sh index a7eaa10..2f03968 100644 --- a/Images/test_plugin.sh +++ b/Images/test_plugin.sh @@ -11,8 +11,10 @@ else REQUESTS_CA_BUNDLE="" pip install pytest; fi; -# clone plugin repository -git clone https://github.com/qiita-spots/${PLUGIN} +if [ "qp-qiime2" != "$PLUGIN" ]; then + # clone plugin repository + git clone https://github.com/qiita-spots/${PLUGIN} +fi; # NOTE: client api reset only works when communicating with Qitta Master, # thus, you need to directly address the port of the master container. Don't @@ -42,4 +44,8 @@ export QIITA_PORT=21174 export QIITA_ROOTCA_CERT=$SSL_CERT_FILE # change into plugin source directory and execute actual tests -cd ${PLUGIN} && pytest +if [ "qp-qiime2" == "$PLUGIN" ]; then + source /opt/conda/etc/profile.d/conda.sh; conda activate /opt/conda/envs/qiime2; cd ${PLUGIN} && pytest; +else + cd ${PLUGIN} && pytest; +fi; From 670cd87f9ba0aae3c1be9fbb781359370dac45fc Mon Sep 17 00:00:00 2001 From: Stefan Janssen Date: Fri, 12 Sep 2025 14:36:25 +0200 Subject: [PATCH 286/287] Update buildContainer.yaml --- .github/workflows/buildContainer.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildContainer.yaml b/.github/workflows/buildContainer.yaml index 7f7c79b..b2eddc4 100644 --- a/.github/workflows/buildContainer.yaml +++ b/.github/workflows/buildContainer.yaml @@ -3,9 +3,12 @@ name: docker on: + pull_request: + branches: + - tinqiita push: branches: - - 'restructure_github_actions' + - tinqiita jobs: make_certificates: From d2f7467e90d3dd68e7bfe0ab3e2323fd8628f9f4 Mon Sep 17 00:00:00 2001 From: Anna-Rehm Date: Thu, 18 Sep 2025 12:06:20 +0200 Subject: [PATCH 287/287] Add tzdata package and configure timezone to run analyses --- Images/qp-qiime2/qp-qiime2.dockerfile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Images/qp-qiime2/qp-qiime2.dockerfile b/Images/qp-qiime2/qp-qiime2.dockerfile index 499f542..629e40c 100644 --- a/Images/qp-qiime2/qp-qiime2.dockerfile +++ b/Images/qp-qiime2/qp-qiime2.dockerfile @@ -15,7 +15,8 @@ RUN apt-get -y --fix-missing install \ python3-dev \ gcc \ build-essential \ - zip + zip \ + tzdata # install miniforge3 for "conda" # see https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile @@ -74,6 +75,15 @@ RUN export QIITA_CONFIG_FP=/qiita/config_qiita_oidc.cfg # let the container know it's plugin name ENV PLUGIN=qp-qiime2 +# configure language +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +# configure timezone +RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime +RUN dpkg-reconfigure -f noninteractive tzdata + + WORKDIR / COPY start_qp-qiime2.sh .

*m5k6c7I4)%5WLQV7*MNHyR7Ds}r@MrO+5ysZ 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 z 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 VFUwCpozvC-{tq6IcPnnA3IGO-q}~7k literal 0 HcmV?d00001 diff --git a/DemoData/zr5156_3V3V4_R1.fastq.gz b/DemoData/zr5156_3V3V4_R1.fastq.gz new file mode 100644 index 0000000000000000000000000000000000000000..8c5dbe1a82f153bcceeb98d2199a580dc2036b77 GIT binary patch literal 168374 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

FXuO^dr5{(^^H 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 bynZsv2(JAl0?^J>{-6H>1Hb61a-#|WZwr6q literal 0 HcmV?d00001 diff --git a/DemoData/zr5156_2V3V4_R1.fastq.gz b/DemoData/zr5156_2V3V4_R1.fastq.gz new file mode 100644 index 0000000000000000000000000000000000000000..8789af7b1389fa60343b116d38cc1c50fe1fff1c GIT binary patch literal 173554 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