Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
461f69f
prepare another setting variable to store plugin coupling thightness
sjanssen2 Aug 15, 2025
fefc02b
provide two functions to retrieve and push file content to qiita master
sjanssen2 Aug 15, 2025
a04beeb
add a configurable parameter to define plugincoupling for plugin
sjanssen2 Aug 15, 2025
8f9fbec
codestyle
sjanssen2 Aug 15, 2025
8d0844d
adapting test to new configuration option
sjanssen2 Aug 15, 2025
47a4551
start working on tests
sjanssen2 Aug 15, 2025
8d22021
check spelling
sjanssen2 Aug 15, 2025
e032053
fixing existing test
sjanssen2 Aug 15, 2025
7d5b098
wrong list index
sjanssen2 Aug 15, 2025
349ab44
initial tests + docstrings
sjanssen2 Aug 18, 2025
1fdf1e5
use a prefix user has access to
sjanssen2 Aug 18, 2025
748f727
remove /
sjanssen2 Aug 18, 2025
8f26804
capitalize comments
sjanssen2 Aug 19, 2025
509b3d5
use qiita branch
sjanssen2 Aug 19, 2025
0cc6a50
specify directory name
sjanssen2 Aug 19, 2025
738ab79
add testing https protocol
sjanssen2 Aug 19, 2025
0849ca7
fix protected
sjanssen2 Aug 19, 2025
e1cb5b6
operate on file copy
sjanssen2 Aug 19, 2025
ba929a2
debug
sjanssen2 Aug 19, 2025
1d26830
avoid //
sjanssen2 Aug 19, 2025
85c40f2
remove trailing /
sjanssen2 Aug 19, 2025
7c46442
remove debug, activate endpoint, reactivate all tests
sjanssen2 Aug 19, 2025
d9543c9
set path to / of only filename is given
sjanssen2 Aug 19, 2025
b9ade44
fix typo
sjanssen2 Aug 20, 2025
e336fbc
enable environment variable, configuration file and default for "plug…
sjanssen2 Aug 27, 2025
c2d5976
revert to qiita dev and remove ENABLE_HTTPS_PLUGIN_FILETRANSFER
sjanssen2 Aug 27, 2025
65e6f48
address Antonio's great suggestions
sjanssen2 Aug 29, 2025
7b6ca63
promoting comment to part of readme
sjanssen2 Aug 29, 2025
296e32c
fix formatting
sjanssen2 Aug 29, 2025
384e97d
"not prefix" did not match properly
sjanssen2 Aug 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/qiita-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
conda activate qiita
export QIITA_ROOTCA_CERT=`pwd`/qiita-dev/qiita_core/support_files/ci_rootca.crt
export QIITA_CONFIG_FP=`pwd`/qiita-dev/qiita_core/support_files/config_test_local.cfg
sed "s#/home/runner/work/qiita/qiita#${PWD}/qiita-dev/#g" `pwd`/qiita-dev/qiita_core/support_files/config_test.cfg > ${QIITA_CONFIG_FP}
sed "s#/home/runner/work/qiita/qiita#${PWD}/qiita-dev#g" `pwd`/qiita-dev/qiita_core/support_files/config_test.cfg > ${QIITA_CONFIG_FP}

export REDBIOM_HOST="http://localhost:7379"

Expand All @@ -104,7 +104,8 @@ jobs:
mkdir -p ${CONDA_PREFIX}/var/run/nginx/
export NGINX_FILE=`pwd`/qiita-dev/qiita_pet/nginx_example.conf
export NGINX_FILE_NEW=`pwd`/qiita-dev/qiita_pet/nginx_example_local.conf
sed "s#/home/runner/work/qiita/qiita#${PWD}/qiita-dev/#g" ${NGINX_FILE} > ${NGINX_FILE_NEW}
sed "s#/home/runner/work/qiita/qiita#${PWD}/qiita-dev#g" ${NGINX_FILE} > ${NGINX_FILE_NEW}
sed -i "s#/Users/username/qiita#${PWD}/qiita-dev#g" ${NGINX_FILE_NEW}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this like required?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 107 is to removed // from some of the urls
line 108 is necessary for the nginx test instance to point to the actual BASE_DATA_DIR within the github action: https://github.com/qiita-spots/qiita/blob/a34dcebc44ea6408340d31ecaf0efd1f78e3cc6b/qiita_pet/nginx_example.conf#L57-L63

nginx -c ${NGINX_FILE_NEW}

echo "3. Setting up qiita"
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,32 @@ Also, if Qiita is running with the default server SSL certificate, you need to e

export QIITA_ROOT_CA=<QIITA_INSTALL_PATH>/qiita_core/support_files/ci_rootca.crt
```

Configure for cloud computing
-----------------------------
In the default scenario, Qiita main and Qiita plugins are executed on the same
machines, maybe spread across a Slurm or other grid compute cluster, but main
and plugins have direct access to all files in `BASE_DATA_DIR`.

This can be different, if you set up Qiita within a cloud compute environment,
where main and plugins do **not** share one file system. In this case, input-
files must first be transferred from main to plugin, then plugin can do its
processing and resulting files must be transferred back to main, once
processing is finished. To achieve this, the qiita_client, as it is part of
each plugin, provides the two functions for this file transfer
`fetch_file_from_central` and `push_file_to_central`. According to
`self._plugincoupling`, these functions operate on different "protocols";
as of 2025-08-29, either "filesystem" or "https". Switch to **"https"** for
cloud environments, default is **filesystem**.

The plugin coupling protocoll can be set in three ways

1. default is always `filesystem`, i.e. `_DEFAULT_PLUGIN_COUPLINGS`
This is to be downward compatible.
2. the plugin configuration can hold a section `network` with an
option `PLUGINCOUPLING`. For old config files, this might not
(yet) be the case. Therefore, we are double checking existance
of this section and parameter here.
Comment on lines +41 to +44
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This confuses me, why have the config-file and the environmental variable? I think just leaving the env var should suffice, but I might be missing something ....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it CAN all be done just by the environment variable. However, qiita collects the plugin configuration files in the PLUGIN_DIR directory. I thought it would be handy to store the protocol in these files, such that a DB reset won't hurt - which is common during testing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you are saying but then this will set that variable for that plugin, meaning that we might need multiple plugins for the same command based on the configuration; right? For example, deblur would need a plugin that uses filesystem and another for https; which I believe we decided it was not desirable but I also know that we are still figuring out this. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is fine as is for your Slurm setup, but agree the config file and env seem a bit redundant.

In a container scenario, the config file would also live within the container and let the plugin know how to communicate with main - no need to obtain this value from the DB. Thus you can have two different container, holding the same plugin, but communicating differently (maybe interesting for long / short distances around the globe?) The DB would then just need to decide which URL to use for triggering, but doesn't need to worry about the protocol

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it - sorry that this is taking longer than expected, but just to confirm, then wouldn't the container always have the env variable set to https; thus, making the config file redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env variable would NOT be set by default, so container reads from config file, except you forcefully want to make the container change its behavior: in this case you can override via env variable

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thank you.

3. you can set the environment variable `QIITA_PLUGINCOUPLING`
Precedence is 3, 2, 1, i.e. the environment variable overrides
the other two ways.
71 changes: 62 additions & 9 deletions qiita_client/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,46 @@ def __init__(self, name, description, can_be_submitted_to_ebi,


class BaseQiitaPlugin(object):
def __init__(self, name, version, description, publications=None):
_DEFAULT_PLUGIN_COUPLINGS = 'filesystem'
_ALLOWED_PLUGIN_COUPLINGS = [_DEFAULT_PLUGIN_COUPLINGS, 'https']

def __init__(self, name, version, description, publications=None,
plugincoupling=_DEFAULT_PLUGIN_COUPLINGS):
logger.debug('Entered BaseQiitaPlugin.__init__()')
self.name = name
self.version = version
self.description = description
self.publications = dumps(publications) if publications else ""

# Depending on your compute architecture, there are multiple options
# available how "thight" plugins are coupled to the central
# Qiita master/workers
# --- filesystem ---
# The default scenario is "filesystem", i.e. plugins as well as
# master/worker have unrestricted direct access to a shared filesystem,
# e.g. a larger volume / directory, defined in the server configuration
# as base_data_dir
# --- https ---
# A second scenario is that your plugins execute as independent jobs on
# another machine, e.g. as docker containers or other cloud techniques.
# Intentionally, you don't want to use a shared filesystem, but you
# have to make sure necessary input files are provided to the
# containerized plugin before execution and resulting files are
# transfered back to the central Qiita master/worker. In this case,
# files are pulled / pushed through functions
# qiita_client.fetch_file_from_central and
# qiita_client.push_file_to_central, respectivey.
# Actually, all files need to be decorated with this function.
# The decision how data are transferred is then made within these two
# functions according to the "plugincoupling" setting.
if plugincoupling not in self._ALLOWED_PLUGIN_COUPLINGS:
raise ValueError(
("valid plugincoupling values are ['%s'], but you "
"provided %s") % (
"', '".join(self._ALLOWED_PLUGIN_COUPLINGS),
plugincoupling))
self.plugincoupling = plugincoupling

# Will hold the different commands
self.task_dict = {}

Expand All @@ -151,7 +184,8 @@ def __init__(self, name, version, description, publications=None):
'QIITA_PLUGINS_DIR', join(expanduser('~'), '.qiita_plugins'))
self.conf_fp = join(conf_dir, "%s_%s.conf" % (self.name, self.version))

def generate_config(self, env_script, start_script, server_cert=None):
def generate_config(self, env_script, start_script, server_cert=None,
plugin_coupling=_DEFAULT_PLUGIN_COUPLINGS):
"""Generates the plugin configuration file

Parameters
Expand All @@ -165,6 +199,9 @@ def generate_config(self, env_script, start_script, server_cert=None):
If the Qiita server used does not have a valid certificate, the
path to the Qiita certificate so the plugin can connect over
HTTPS to it
plugin_coupling : str
Type of coupling of plugin to central for file exchange.
Valid values: see _ALLOWED_PLUGIN_COUPLINGS.
"""
logger.debug('Entered BaseQiitaPlugin.generate_config()')
sr = SystemRandom()
Expand All @@ -178,7 +215,8 @@ def generate_config(self, env_script, start_script, server_cert=None):
f.write(CONF_TEMPLATE % (self.name, self.version, self.description,
env_script, start_script,
self._plugin_type, self.publications,
server_cert, client_id, client_secret))
server_cert, client_id, client_secret,
plugin_coupling))

def _register_command(self, command):
"""Registers a command in the plugin
Expand All @@ -188,8 +226,8 @@ def _register_command(self, command):
command: QiitaCommand
The command to be added to the plugin
"""
logger.debug(
f'Entered BaseQiitaPlugin._register_command({command.name})')
logger.debug('Entered BaseQiitaPlugin._register_command(%s)' %
command.name)
self.task_dict[command.name] = command

def _register(self, qclient):
Expand Down Expand Up @@ -244,14 +282,23 @@ def __call__(self, server_url, job_id, output_dir):
with open(self.conf_fp, 'U') as conf_file:
config.readfp(conf_file)

plugincoupling = self._DEFAULT_PLUGIN_COUPLINGS
if config.has_section('network') and \
config.has_option('network', 'PLUGINCOUPLING'):
plugincoupling = config.get('network', 'PLUGINCOUPLING')
if 'QIITA_PLUGINCOUPLING' in environ.keys() and \
environ['QIITA_PLUGINCOUPLING'] is not None:
plugincoupling = environ['QIITA_PLUGINCOUPLING']

qclient = QiitaClient(server_url, config.get('oauth2', 'CLIENT_ID'),
config.get('oauth2', 'CLIENT_SECRET'),
# for this group of tests, confirm optional
# ca_cert parameter works as intended. Setting
# this value will prevent underlying libraries
# from validating the server's cert using
# certifi's pem cache.
ca_cert=config.get('oauth2', 'SERVER_CERT'))
ca_cert=config.get('oauth2', 'SERVER_CERT'),
plugincoupling=plugincoupling)

if job_id == 'register':
self._register(qclient)
Expand Down Expand Up @@ -314,9 +361,11 @@ class QiitaTypePlugin(BaseQiitaPlugin):
_plugin_type = "artifact definition"

def __init__(self, name, version, description, validate_func,
html_generator_func, artifact_types, publications=None):
html_generator_func, artifact_types, publications=None,
plugincoupling=BaseQiitaPlugin._DEFAULT_PLUGIN_COUPLINGS):
super(QiitaTypePlugin, self).__init__(name, version, description,
publications=publications)
publications=publications,
plugincoupling=plugincoupling)

logger.debug('Entered QiitaTypePlugin.__init__()')
self.artifact_types = artifact_types
Expand Down Expand Up @@ -382,4 +431,8 @@ def register_command(self, command):
[oauth2]
SERVER_CERT = %s
CLIENT_ID = %s
CLIENT_SECRET = %s"""
CLIENT_SECRET = %s

[network]
PLUGINCOUPLING = %s
"""
Loading
Loading