Skip to content

Add Plugin template support #1389

Description

@elliotgunton

Is your feature request related to a problem? Please describe.
#1387

Plugin templates aren't directly supported by Hera; you have to use the model classes. It should be possible to use the plugins from the plugin directory using Hera's custom classes. Couple of examples:

Hello world

from hera.workflows import Workflow
from hera.workflows.models import Template, Plugin

class MyPlugin(Plugin):
    hello: dict = {}

w = Workflow(
    generate_name="hello-example-",
    entrypoint="main",
)

# unfortunately need to append as context manager doesn't
# work for model classes:

w.templates.append(
    Template(
        name="main",
        plugin=MyPlugin(
            hello={},
        ),
    )
)

For YAML:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: hello-example-
spec:
  entrypoint: main
  templates:
  - name: main
    plugin:
      hello: {}

Slack plugin

from hera.workflows import Workflow
from hera.workflows.models import Template, Plugin

from pydantic.v1 import BaseModel


class Slack(BaseModel):
    text: str

class SlackPlugin(Plugin):
    slack: Slack

w = Workflow(
    generate_name="slack-example-",
    entrypoint="main",
)

w.templates.append(
    Template(
        name="main",
        plugin=SlackPlugin(
            slack=Slack(
                text="{{workflow.name}} finished!",
            ),
        ),
    )
)

For YAML:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: slack-example-
spec:
  entrypoint: main
  templates:
  - name: main
    plugin:
      slack:
        text: '{{workflow.name}} finished!'

Describe the solution you'd like
These examples should be possible using a new PluginTemplate class which has the same behaviour under Workflow and DAG context managers as Scripts/Containers/etc.

Having the examples above in the repo is not currently possible as they fail testing due to the roundtrip test (assert workflow == HeraWorkflow.from_dict(workflow.to_dict())) not understanding how to interpret the value under plugin (i.e. it drops it). LHS vs RHS:

...
+ plugin=SlackPlugin(slack=Slack(text='{{workflow.name}} finished!')),
...

- plugin=Plugin(),

E.g. hello world would become:

from hera.workflows import PluginTemplate, Workflow
from hera.workflows.models import Template, Plugin


class HelloWorldPlugin(Plugin):
    hello: dict

with Workflow(
    generate_name="hello-example-",
    entrypoint="main",
) as w:
    PluginTemplate(
        name="main",
        plugin=HelloWorldPlugin(
            hello={},
        ),
    )

Using a DAG to show the callable behaviour:

from hera.workflows import DAG, PluginTemplate, Workflow
from hera.workflows.models import Plugin


class HelloWorldPlugin(Plugin):
    hello: dict

with Workflow(
    generate_name="hello-example-",
    entrypoint="main",
) as w:
    hello_template = PluginTemplate(
        name="hello",
        plugin=HelloWorldPlugin(
            hello={},
        ),
    )
    with DAG(name="main") as d:
        hello_template(name="hello-1")
        hello_template(name="hello-2")

Describe alternatives you've considered
Use the model classes, not much better than YAML 🙂

Additional context
Slack thread https://cloud-native.slack.com/archives/C03NRMD9KPY/p1747674689849999

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions