How can I enable external plugins on openedx setup via tutor?

Hi,
I need help adding this plugin to tutor that is currently deployed on my local machine:

All the plugin examples I have seen are for plugins that are used for config changes but not for adding any external plugin.

Hi @utsavjari
I think the guidance you need should be here: Installing extra xblocks and requirements
example:
tutor config save --append OPENEDX_EXTRA_PIP_REQUIREMENTS=git+https://github.com/Pearson-Advance/openedx-lti-tool-plugin.git

@feanil do you have any advice here? (installing the openedx-lti-tool-plugin)

I agree with @joel.edwards , this is just adding a new requirement.

You’ll also need to set a couple of settings, you can make a small quick plugin to do that like in this example here: Examples — Tutor documentation

1 Like

Thanks for the instructions, I have created the plugin and addded it

from tutor import hooks
hooks.Filters.ENV_PATCHES.add_item((“lms-env-features”,“ENABLE_LTI_PROVIDER: true”))
hooks.Filters.ENV_PATCHES.add_item((“lms-env-features”,“OLTITP_ENABLE_LTI_TOOL: true”))

After adding it I enabled the plugin and ran

tutor images build all

Then ran the command shared by @joel.edwards
tutor config save --append OPENEDX_EXTRA_PIP_REQUIREMENTS=git+https://github.com/Pearson-Advance/openedx-lti-tool-plugin.git

and ran
tutor images build openedx

but after running above command I am getting some error, below is the stack trace (I am unable to upload txt files on forum so adding below, everything below is the stacktrace but somehow text field is formatting it badly):

Building image docker.io/overhangio/openedx:20.0.1-indigodocker buildx build --tag=docker.io/overhangio/openedx:20.0.1-indigo --output=type=docker --cache-from=type=registry,ref=docker.io/overhangio/openedx:20.0.1-indigo-cache /home/utsav/.local/share/tutor/env/build/openedx[+] Building 9.2s (53/72)                                                                                                        docker:default=> [internal] load .dockerignore                                                                                                          0.0s=> => transferring context: 2B                                                                                                            0.0s=> [internal] load build definition from Dockerfile                                                                                       0.0s=> => transferring dockerfile: 12.42kB                                                                                                    0.0s=> resolve image config for docker.io/docker/dockerfile:1                                                                                 0.8s=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:38387523653efa0039f8e1c89bb74a30504e76ee9f565e25c9a09841f9427b05            0.0s=> [internal] load build definition from Dockerfile                                                                                       0.0s=> [internal] load metadata for docker.io/powerman/dockerize:0.19.0                                                                       1.6s=> [internal] load metadata for                                                                             1.8s=> [internal] load .dockerignore                                                                                                          0.0s=> importing cache manifest from docker.io/overhangio/openedx:20.0.1-indigo-cache                                                         3.1s=> [internal] load build context                                                                                                          0.1s=> => transferring context: 3.79MB                                                                                                        0.1s=> [code 3/4] ADD --keep-git-dir=true  .                                        2.9s=> FROM docker.io/powerman/dockerize:0.19.0@sha256:a34158d699e065609fc845e7cdc1e070f185afdbca317fe4931aaea04818f8bf                       0.0s=> [minimal 1/2] FROM               0.0s=> => resolve                       0.0s=> CACHED [minimal 2/2] RUN --mount=type=cache,target=/var/cache/apt,sharing=locked     --mount=type=cache,target=/var/lib/apt,sharing=l  0.0s=> CACHED [production  1/37] RUN --mount=type=cache,target=/var/cache/apt,sharing=locked     --mount=type=cache,target=/var/lib/apt,shar  0.0s=> CACHED [production  2/37] RUN if [ “1000” = 0 ]; then echo “app user may not be root” && false; fi                                     0.0s=> CACHED [production  3/37] RUN useradd --no-log-init --home-dir /openedx --create-home --shell /bin/bash --uid 1000 app                 0.0s=> CACHED [production  4/37] COPY --link --from=docker.io/powerman/dockerize:0.19.0 /usr/local/bin/dockerize /usr/local/bin/dockerize     0.0s=> CACHED [code 1/4] RUN mkdir -p /openedx/edx-platform                                                                                   0.0s=> CACHED [code 2/4] WORKDIR /openedx/edx-platform                                                                                        0.0s=> CACHED [code 3/4] ADD --keep-git-dir=true  .                                 0.0s=> CACHED [code 4/4] RUN git config --global user.email “tutor@overhang.io”   && git config --global user.name “Tutor”                    0.0s=> CACHED [edx-platform 1/1] COPY --from=code /openedx/edx-platform /                                                                     0.0s=> CACHED [production  5/37] COPY --link --chown=1000:1000 --from=edx-platform / /openedx/edx-platform                                    0.0s=> CACHED [python 1/4] RUN --mount=type=cache,target=/var/cache/apt,sharing=locked     --mount=type=cache,target=/var/lib/apt,sharing=lo  0.0s=> CACHED [python 2/4] RUN git clone  /opt/pyenv --branch v2.3.36 --depth 1                                 0.0s=> CACHED [python 3/4] RUN /opt/pyenv/bin/pyenv install 3.11.8                                                                            0.0s=> CACHED [python 4/4] RUN /opt/pyenv/versions/3.11.8/bin/python -m venv /openedx/venv                                                    0.0s=> CACHED [production  6/37] COPY --link --chown=1000:1000 --from=python /opt/pyenv /opt/pyenv                                            0.0s=> CACHED [python-requirements 1/7] RUN --mount=type=cache,target=/var/cache/apt,sharing=locked     --mount=type=cache,target=/var/lib/a  0.0s=> CACHED [python-requirements 2/7] RUN --mount=type=cache,target=/openedx/.cache/pip,sharing=shared     pip install     setuptools==69.  0.0s=> CACHED [python-requirements 3/7] RUN --mount=type=bind,from=edx-platform,source=/requirements/edx/base.txt,target=/openedx/edx-platfo  0.0s=> CACHED [python-requirements 4/7] RUN --mount=type=cache,target=/openedx/.cache/pip,sharing=shared     pip install     django-redis==5  0.0s=> CACHED [python-requirements 5/7] RUN --mount=type=cache,target=/openedx/.cache/pip,sharing=shared     UWSGI_PROFILE_OVERRIDE=“xml=no”  0.0s=> CACHED [python-requirements 6/7] RUN pip install “openedx-scorm-xblock>=19.0.0,<20.0.0”                                                0.0s=> CACHED [python-requirements 7/7] RUN --mount=type=cache,target=/openedx/.cache/pip,sharing=shared     pip install 'git+https://github  0.0s=> CACHED [production  7/37] COPY --link --chown=1000:1000 --from=python-requirements /openedx/venv /openedx/venv                         0.0s=> CACHED [production  8/37] COPY --link --chown=1000:1000 --from=python-requirements /mnt /mnt                                           0.0s=> CACHED [nodejs-requirements 1/4] RUN pip install nodeenv==1.9.1                                                                        0.0s=> CACHED [nodejs-requirements 2/4] RUN nodeenv /openedx/nodeenv --node=18.20.1 --prebuilt                                                0.0s=> CACHED [nodejs-requirements 3/4] WORKDIR /openedx/edx-platform                                                                         0.0s=> CACHED [nodejs-requirements 4/4] RUN --mount=type=bind,from=edx-platform,source=/package.json,target=/openedx/edx-platform/package.js  0.0s=> CACHED [production  9/37] COPY --link --chown=1000:1000 --from=nodejs-requirements /openedx/nodeenv /openedx/nodeenv                   0.0s=> CACHED [production 10/37] COPY --link --chown=1000:1000 --from=nodejs-requirements /openedx/edx-platform/node_modules /openedx/node_m  0.0s=> CACHED [production 11/37] RUN ln -s /openedx/node_modules /openedx/edx-platform/node_modules                                           0.0s=> CACHED [production 12/37] WORKDIR /openedx/edx-platform                                                                                0.0s=> CACHED [production 13/37] RUN pip install -e .                                                                                         0.0s=> CACHED [production 14/37] RUN mkdir -p /openedx/config ./lms/envs/tutor ./cms/envs/tutor                                               0.0s=> CACHED [production 15/37] COPY --chown=app:app revisions.yml /openedx/config/                                                          0.0s=> CACHED [production 16/37] COPY --chown=app:app settings/lms/.py ./lms/envs/tutor/                                                     0.0s=> CACHED [production 17/37] COPY --chown=app:app settings/cms/.py ./cms/envs/tutor/                                                     0.0s=> CACHED [production 18/37] RUN make clean_translations                                                                                  0.0s=> ERROR [production 19/37] RUN ./manage.py lms --settings=tutor.i18n pull_plugin_translations --verbose --repository='openedx/openedx-t  3.1s
[production 19/37] RUN ./manage.py lms --settings=tutor.i18n pull_plugin_translations --verbose --repository=‘openedx/openedx-translations’ --revision=‘release/teak.2’:2.852 Traceback (most recent call last):2.852   File “/openedx/edx-platform/./manage.py”, line 99, in 2.852     execute_from_command_line([sys.argv[0]] + django_args)2.852   File “/openedx/venv/lib/python3.11/site-packages/django/core/management/init.py”, line 442, in execute_from_command_line2.854     utility.execute()2.854   File “/openedx/venv/lib/python3.11/site-packages/django/core/management/init.py”, line 416, in execute2.854     django.setup()2.854   File “/openedx/venv/lib/python3.11/site-packages/django/init.py”, line 24, in setup2.854     apps.populate(settings.INSTALLED_APPS)2.854   File “/openedx/venv/lib/python3.11/site-packages/django/apps/registry.py”, line 116, in populate2.855     app_config.import_models()2.855   File “/openedx/venv/lib/python3.11/site-packages/django/apps/config.py”, line 269, in import_models2.856     self.models_module = import_module(models_module_name)2.856                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^2.856   File “/opt/pyenv/versions/3.11.8/lib/python3.11/importlib/init.py”, line 126, in import_module2.856     return _bootstrap._gcd_import(name[level:], package, level)2.856            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^2.856   File “”, line 1204, in _gcd_import2.856   File “”, line 1176, in _find_and_load2.856   File “”, line 1147, in _find_and_load_unlocked2.856   File “”, line 690, in _load_unlocked2.856   File “”, line 940, in exec_module2.856   File “”, line 241, in _call_with_frames_removed2.856   File “/openedx/edx-platform/openedx/core/djangoapps/config_model_utils/models.py”, line 23, in 2.856     from openedx.core.djangoapps.content.course_overviews.models import CourseOverview2.856   File “/openedx/edx-platform/openedx/core/djangoapps/content/course_overviews/models.py”, line 26, in 2.857     from lms.djangoapps.courseware.model_data import FieldDataCache2.857   File “/openedx/edx-platform/lms/djangoapps/courseware/model_data.py”, line 40, in 2.857     from xmodule.modulestore.django import modulestore  # lint-amnesty, pylint: disable=wrong-import-order2.857     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^2.857   File “/openedx/edx-platform/xmodule/modulestore/django.py”, line 31, in 2.857     from xmodule.modulestore.mixed import MixedModuleStore  # lint-amnesty, pylint: disable=wrong-import-position2.857     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^2.857   File “/openedx/edx-platform/xmodule/modulestore/mixed.py”, line 15, in 2.857     from openedx_events.content_authoring.data import CourseData, XBlockData2.857   File “/openedx/venv/lib/python3.11/site-packages/openedx_events/content_authoring/data.py”, line 15, in 2.857     from opaque_keys.edx.locator import (2.857 ImportError: cannot import name ‘LibraryCollectionLocator’ from ‘opaque_keys.edx.locator’ (/openedx/venv/lib/python3.11/site-packages/opaque_keys/edx/locator.py)

Dockerfile:194
192 |     # Pull latest translations via atlas193 |     RUN make clean_translations194 | >>> RUN ./manage.py lms --settings=tutor.i18n pull_plugin_translations --verbose --repository=‘openedx/openedx-translations’ --revision=‘release/teak.2’195 |     RUN ./manage.py lms --settings=tutor.i18n pull_xblock_translations --repository=‘openedx/openedx-translations’ --revision=‘release/teak.2’196 |     RUN atlas pull --repository=‘openedx/openedx-translations’ --revision=‘release/teak.2’  \
ERROR: failed to solve: process “/bin/sh -c ./manage.py lms --settings=tutor.i18n pull_plugin_translations --verbose --repository=‘openedx/openedx-translations’ --revision=‘release/teak.2’” did not complete successfully: exit code: 1Error: Command failed with status 1: docker buildx build --tag=docker.io/overhangio/openedx:20.0.1-indigo --output=type=docker --cache-from=type=registry,ref=docker.io/overhangio/openedx:20.0.1-indigo-cache /home/utsav/.local/share/tutor/env/build/openedx 

The plugin I have used have mentioned using Olive release but I am not sure if it’s compatible with tutor’s latest version, is there anyway to find it out?

it looks like LibraryCollectionLocator was only added in version 2.11.0 of opaque-keys but the requirements of openedx-lt-tool-plugin show edx-opaque-keys==2.3.0

As you’ve mentioned, Olive is specified in the plugin so it’s possible this was intended specifically for that release and has not been updated to support latest releases. You might be able to work around this by editing the requirements so it installs the matching latest version edx-opaque-keys==3.0.0 in edx-platform, however given that this has probably not been tested in latest releases, your results may vary. My expectation is that you probably want to use another plugin that has been validated for your chosen version of Tutor

Hey, actually i tried upgrading the plugin requirements and was able to build the container, I have also setup the LTI tool in canvas, but while launching the app and on redirection to openedx I am facing a “404 not found” error. Do I need to setup anything extra in openedx to enable LTI?

Regret I’m unable to assist you further as I honestly have no experience with LTI integration nor these plugins, all the info I managed to find thus far was just from digging through the docs/code. Hopefully someone else in the community would be better positioned to assist you :slight_smile:

No worries. thanks a lot for your help

Have you checked out the LTI docs? The landing page is here: About the LTI Component — Latest documentation and at the bottom there’s a tree of docs that may help you figure out what you need to set up