Skip to content
This repository has been archived by the owner on May 2, 2024. It is now read-only.

Create a pluggable "jobs"/"tasks" interface #75

Closed
kdmccormick opened this issue Jun 2, 2022 · 11 comments
Closed

Create a pluggable "jobs"/"tasks" interface #75

kdmccormick opened this issue Jun 2, 2022 · 11 comments
Assignees
Labels
enhancement Relates to new features or improvements to existing features

Comments

@kdmccormick
Copy link
Collaborator

kdmccormick commented Jun 2, 2022

Context

Originally discussed here: overhangio/tutor#643 (comment) .

Problem

There is no perfect way for Tutor or its plugins to define "tasks" (initialization tasks, setup tasks, test data provisioning, whatever) to be run within containers

Of course, Tutor/plugins can define runnable scripts by putting them in their own services' /openedx/bin folder; for example, Tutor adds /openedx/bin/openedx-assets to the openedx image, allowing us to run tutor dev run openedx-assets build. However, this only works within the plugin that defines the image's Dockerfile. One could not easily write a plugin that runs data management commands in the LMS container, because the openedx Dockerfile is in Tutor core, which plugins cannot easily add scripts to.

Relevant issues:

Proposals

(For what it's worth: I like proposal 1 better, and I'm not sure proposal 2 would even work. I just want to make sure we're considering existing extension points before adding a new one.)

1. Introduce a tasks subcommand and filter

  • Introduce a new filter as described in this comment.
  • Add a new subcommand: tutor dev tasks ....
  • Running tutor MODE tasks TASKNAME [ARGS...] would:
    • look up TASKNAME from CLI_TASKS in order to find the list of (service, command) pairs.
    • for each pair, run command within service
      • use docker-compose run for dev/local, and use kubectl exec for k8s.

2. Allow plugins to add files to the openedx build context

Currently, plugin templates are all rendered into $(tutor config printroot)/env/plugins/ folder. The openedx Docker image is built from $(tutor config printroot)/env/build/openedx/. So, plugins cannot possibly add new templates that would be rendered into the openedx build context.

But what if they could? What if the openedx Docker build context was at, say, $(tutor config printroot)/env/plugins/tutor-openedx/build? I think a plugin could then define a script at myplugin/templates/tutor-openedx/build/bin/my-cool-task-script, for the openedx Dockerfile to make available when it runs:

# Copy scripts
COPY --chown=app:app ./bin /openedx/bin
RUN chmod a+x /openedx/bin/*
ENV PATH /openedx/bin:${PATH}

The task would be runnable via:

tutor dev run lms my-cool-task-script

A large, obvious downside to this is that it would require an image rebuild.

Acceptance Criteria

Per discussion below, implement Proposal 1.

@kdmccormick kdmccormick changed the title Add a pluggable tutor tasks interface Create a pluggable "tasks" interface Jun 23, 2022
@kdmccormick
Copy link
Collaborator Author

@regisb Lower priority, but when you have time, can you look at this issue as well as its sister issue and let me know what you think of the proposed solutions?

@regisb
Copy link

regisb commented Jul 4, 2022

Note that solution 2) is now possible, as plugins can render files outside of their own plugin folder. Still, I think that solution is not the best one because (as you mentioned) users need to rebuild their Docker images. Also, the same solution cannot be applied to images other than openedx.

I think that solution 1) is the best, with one caveat: each task should support running multiple commands in different containers. Thus, the filter signature would be: CLI_TASKS: list[tuple[task_name: str, tuple[service: str, command: str]]]. These tasks would be run with docker-compose run in local/dev and kubectl exec in k8s.

@kdmccormick
Copy link
Collaborator Author

@regisb Sounds good! I'll get to work on this sooner than later since it affects a couple other open issues.

Here's the Filter doc I'll work off of. I came up with a slightly different type signature than you: I have tuple[service: str, command: str] wrapped in an additional list[...]. I believe it matches the design you describe.

#: List command line interface (CLI) tasks.
#:  
#: :parameter list[tuple[str, list[tuple[str, str]]]] tasks:
#:
#:   A list of (``task_name``, ``task_commands``) tuples. Each tuple describes a CLI task:
#: 
#:    - ``task_name`` is the string used to invoke the task on the CLI, e.g. ``tutor local task <task_name>``
#:    - ``task_commands`` are a list of (``service``, ``command``) tuples. When the task
#:      is invoked, each shell ``command`` in the list will be run in its corresponding ``service``.
CLI_TASKS = filters.get("cli:tasks")

@kdmccormick kdmccormick moved this from Backlog to Next Up in Tutor DevEnv Adoption Jul 8, 2022
@kdmccormick
Copy link
Collaborator Author

kdmccormick commented Jul 8, 2022

Oh, and @regisb , what exact syntax do you prefer? Considering a task named "dostuff", we could have:

  1. tutor local task dostuff
  2. tutor local runtask dostuff
  3. tutor local tasks dostuff
  4. tutor local dostuff

I have slight lean towards 2 or 4, because they follow the general tutor <mode> <verb> ... form that you've established, but I think they are all OK options.

The other nice thing about form 4 is that we could implement built-in things like importdemocourse as tasks without anyone needing to know that they're tasks under the hood.

@regisb
Copy link

regisb commented Jul 11, 2022

I believe it matches the design you describe.

Yes it does, and it's more elegant. 👌

what exact syntax do you prefer?

Hmmm I'm not sure. Implementing (4) would be awkward because the "dostuff" task would need to be added as a subcommand of the "local" group. "runtask dostuff" would work, but... consider the case when we want to do more with tasks than just executing them. For instance, we might want to print out a list of available tasks. To do that we would have to run tutor local runtask list, which is not very adequate. We could write instead tutor local runtask --list... but I'm not a big fan of "runtask". I think it's not a verb that makes a lot of sense for many non-technical people. Also, it's very similar to tutor local run, which is a totally different thing, obviously.

I guess that the "logical" way of running a task would be with tutor local tasks run dostuff:

tutor local tasks run createuser --superuser --staff example example@example.org
tutor local tasks run importdemocourse
tutor local tasks run init
tutor local tasks run settheme indigo

But that 4th level command is really a mouthful...

I'm not being very constructive here... To summarize, I'd like to use tutor local runtask dostuff, but with a better verb than "runtask". Maybe "do"? That would result in:

tutor local do createuser --superuser --staff example example@example.org
etc.

If we go with "do" I feel like "job" is a better noun than "task".

Long story short: I don't have a very strong opinion here. I'll trust your judgement.

@kdmccormick kdmccormick self-assigned this Jul 11, 2022
@kdmccormick kdmccormick moved this to To Do - Prioritized for Current Sprint in Axim Engineering Tasks Jul 11, 2022
@kdmccormick
Copy link
Collaborator Author

@regisb If we called them "jobs" would that conflict with the existing meaning of "job" in Tutor?

@kdmccormick
Copy link
Collaborator Author

tutor local do createuser --superuser --staff example example@example.org

I like this syntax. I'll start work on it.

@kdmccormick
Copy link
Collaborator Author

@regisb I've begun work on this and found it to be a very interesting feature. You can see my progress and notes here: kdmccormick/tutor#13

@kdmccormick kdmccormick moved this from To Do - Prioritized for Current Sprint to In Progress in Axim Engineering Tasks Jul 13, 2022
@kdmccormick kdmccormick moved this from Next Up to In Progress in Tutor DevEnv Adoption Jul 14, 2022
@kdmccormick kdmccormick added enhancement Relates to new features or improvements to existing features refactor labels Jul 25, 2022
@kdmccormick
Copy link
Collaborator Author

A few notes for anyone following along:

Also, I've been thinking about the terminology. To me, a "task" seems like a part of a "job" (the GitHub Actions YAML schema agrees). So, I think:

  • "jobs" should describe the overarching, definable processes
    • for example: init, pre-init, settheme, prepare-repo-for-development, etc
  • "tasks" should describe a command to be run within a service, as part of a job
    • for example, ("init", "lms", ("sh", "tasks/lms/init"))

As for the filter names and schemas, I am leaning:

  • JOB_TASKS: (job_name: str, task_service: str, task_command: tuple[str, ...])
  • JOB_HELPTEXTS: (job_name: str, helptext: str)

@kdmccormick kdmccormick changed the title Create a pluggable "tasks" interface Create a pluggable "jobs"/"tasks" interface Jul 29, 2022
@kdmccormick kdmccormick moved this from In Progress to To Do - Prioritized for Current Sprint in Axim Engineering Tasks Aug 8, 2022
@kdmccormick
Copy link
Collaborator Author

@regisb will be taking it from here.

regisb added a commit to overhangio/tutor that referenced this issue Oct 21, 2022
We introduce a new filter to implement custom commands in arbitrary containers.
It becomes easy to write convenient ad-hoc commands that users will
then be able to run either on Kubernetes or locally using a documented CLI.

Pluggable jobs are declared as Click commands and are responsible for
parsing their own arguments. See the new CLI_DO_COMMANDS filter.

Close openedx-unsupported/wg-developer-experience#75
regisb added a commit to overhangio/tutor that referenced this issue Oct 21, 2022
We introduce a new filter to implement custom commands in arbitrary containers.
It becomes easy to write convenient ad-hoc commands that users will
then be able to run either on Kubernetes or locally using a documented CLI.

Pluggable jobs are declared as Click commands and are responsible for
parsing their own arguments. See the new CLI_DO_COMMANDS filter.

Close openedx-unsupported/wg-developer-experience#75
@kdmccormick kdmccormick moved this from 🛠️ In Progress to 👀 In Review in Tutor DevEnv Adoption Nov 1, 2022
regisb added a commit to overhangio/tutor that referenced this issue Nov 8, 2022
We introduce a new filter to implement custom commands in arbitrary containers.
It becomes easy to write convenient ad-hoc commands that users will
then be able to run either on Kubernetes or locally using a documented CLI.

Pluggable jobs are declared as Click commands and are responsible for
parsing their own arguments. See the new CLI_DO_COMMANDS filter.

Close openedx-unsupported/wg-developer-experience#75
regisb added a commit to overhangio/tutor that referenced this issue Nov 8, 2022
We introduce a new filter to implement custom commands in arbitrary containers.
It becomes easy to write convenient ad-hoc commands that users will
then be able to run either on Kubernetes or locally using a documented CLI.

Pluggable jobs are declared as Click commands and are responsible for
parsing their own arguments. See the new CLI_DO_COMMANDS filter.

Close openedx-unsupported/wg-developer-experience#75
regisb added a commit to overhangio/tutor that referenced this issue Nov 15, 2022
We introduce a new filter to implement custom commands in arbitrary containers.
It becomes easy to write convenient ad-hoc commands that users will
then be able to run either on Kubernetes or locally using a documented CLI.

Pluggable jobs are declared as Click commands and are responsible for
parsing their own arguments. See the new CLI_DO_COMMANDS filter.

Close openedx-unsupported/wg-developer-experience#75
regisb added a commit to overhangio/tutor that referenced this issue Nov 15, 2022
We introduce a new filter to implement custom commands in arbitrary containers.
It becomes easy to write convenient ad-hoc commands that users will
then be able to run either on Kubernetes or locally using a documented CLI.

Pluggable jobs are declared as Click commands and are responsible for
parsing their own arguments. See the new CLI_DO_COMMANDS filter.

Close openedx-unsupported/wg-developer-experience#75
@kdmccormick
Copy link
Collaborator Author

This is complete.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement Relates to new features or improvements to existing features
Projects
None yet
Development

No branches or pull requests

2 participants