Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Description: Add Optional Argo Workflow–Level Configuration for Executor Plugins
Author: [ntny](https://github.com/ntny)
Component: General
Issues: 15234

This PR allows configuring the Argo Workflow Executor Plugin for a specific Argo Workflow directly within the Workflow spec.
This feature is enabled via the `ARGO_WORKFLOW_LEVEL_EXECUTOR_PLUGINS=true` controller env variable


apiVersion: apps/v1
kind: Deployment
metadata:
name: workflow-controller
spec:
template:
spec:
containers:
- name: workflow-controller
env:
- name: ARGO_WORKFLOW_LEVEL_EXECUTOR_PLUGINS
value: "true"

Sample executor plugin definition in the Argo workflow spec:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: wf-level-plugin
namespace: argo
spec:
entrypoint: hello-hello-hello
executorPlugins:
- metadata:
name: print-message-plugin
spec:
sidecar:
container:
name: print-message-plugin
image: print-message-plugin:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 250m
memory: 64Mi

The definition of the step that uses the plugin is the same for both global and workflow-level specs:

templates:
- name: hello-hello-hello
steps:
- - name: hello1
template: print-message
arguments:
parameters:
- name: message
value: "hello1"
- name: print-message # step which use the plugin
inputs:
parameters:
- name: message
plugin:
print-message-plugin:
args: ["{{inputs.parameters.message}}"]
20 changes: 12 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ STATIC_FILES ?= $(shell [ $(DEV_BRANCH) = true ] && echo false || echo
endif

# -- install & run options
PROFILE ?= minimal
KUBE_NAMESPACE ?= argo # namespace where Kubernetes resources/RBAC will be installed
PLUGINS ?= $(shell [ $(PROFILE) = plugins ] && echo true || echo false)
UI ?= false # start the UI with HTTP
UI_SECURE ?= false # start the UI with HTTPS
API ?= $(UI) # start the Argo Server
TASKS := controller
PROFILE ?= minimal
KUBE_NAMESPACE ?= argo # namespace where Kubernetes resources/RBAC will be installed
PLUGINS ?= $(shell [ $(PROFILE) = plugins ] && echo true || echo false)
WORKFLOW_LEVEL_PLUGINS ?= false
UI ?= false # start the UI with HTTP
UI_SECURE ?= false # start the UI with HTTPS
API ?= $(UI) # start the Argo Server
TASKS := controller
ifeq ($(API),true)
TASKS := controller server
endif
Expand Down Expand Up @@ -673,6 +674,9 @@ ifneq ($(UI),true)
endif
ifneq ($(PLUGINS),true)
@echo "⚠️ not starting plugins. If you want to test plugins, run 'make start PROFILE=plugins' to start it"
endif
ifneq ($(WORKFLOW_LEVEL_PLUGINS),true)
@echo "⚠️ not starting workflow-level plugins. If you want to test workflow-level plugins, run 'make start WORKFLOW_LEVEL_PLUGINS=true' to start it"
endif
# Check dex, minio, postgres and mysql are in hosts file
ifeq ($(AUTH_MODE),sso)
Expand All @@ -683,7 +687,7 @@ endif
grep '127.0.0.1.*postgres' /etc/hosts
grep '127.0.0.1.*mysql' /etc/hosts
ifeq ($(RUN_MODE),local)
env DEFAULT_REQUEUE_TIME=$(DEFAULT_REQUEUE_TIME) ARGO_SECURE=$(SECURE) ALWAYS_OFFLOAD_NODE_STATUS=$(ALWAYS_OFFLOAD_NODE_STATUS) ARGO_LOGLEVEL=$(LOG_LEVEL) UPPERIO_DB_DEBUG=$(UPPERIO_DB_DEBUG) ARGO_AUTH_MODE=$(AUTH_MODE) ARGO_NAMESPACED=$(NAMESPACED) ARGO_NAMESPACE=$(KUBE_NAMESPACE) ARGO_MANAGED_NAMESPACE=$(MANAGED_NAMESPACE) ARGO_EXECUTOR_PLUGINS=$(PLUGINS) ARGO_POD_STATUS_CAPTURE_FINALIZER=$(POD_STATUS_CAPTURE_FINALIZER) ARGO_UI_SECURE=$(UI_SECURE) ARGO_BASE_HREF=$(BASE_HREF) PROFILE=$(PROFILE) kit $(TASKS)
env DEFAULT_REQUEUE_TIME=$(DEFAULT_REQUEUE_TIME) ARGO_SECURE=$(SECURE) ALWAYS_OFFLOAD_NODE_STATUS=$(ALWAYS_OFFLOAD_NODE_STATUS) ARGO_LOGLEVEL=$(LOG_LEVEL) UPPERIO_DB_DEBUG=$(UPPERIO_DB_DEBUG) ARGO_AUTH_MODE=$(AUTH_MODE) ARGO_NAMESPACED=$(NAMESPACED) ARGO_NAMESPACE=$(KUBE_NAMESPACE) ARGO_MANAGED_NAMESPACE=$(MANAGED_NAMESPACE) ARGO_EXECUTOR_PLUGINS=$(PLUGINS) ARGO_WORKFLOW_LEVEL_EXECUTOR_PLUGINS=$(WORKFLOW_LEVEL_PLUGINS) ARGO_POD_STATUS_CAPTURE_FINALIZER=$(POD_STATUS_CAPTURE_FINALIZER) ARGO_UI_SECURE=$(UI_SECURE) ARGO_BASE_HREF=$(BASE_HREF) PROFILE=$(PROFILE) kit $(TASKS)
endif

.PHONY: wait
Expand Down
50 changes: 50 additions & 0 deletions api/jsonschema/schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions api/openapi-spec/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 21 additions & 19 deletions cmd/workflow-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,24 @@ const (
// NewRootCommand returns an new instance of the workflow-controller main entrypoint
func NewRootCommand() *cobra.Command {
var (
clientConfig clientcmd.ClientConfig
configMap string // --configmap
executorImage string // --executor-image
executorImagePullPolicy string // --executor-image-pull-policy
logLevel string // --loglevel
glogLevel int // --gloglevel
logFormat string // --log-format
workflowWorkers int // --workflow-workers
workflowTTLWorkers int // --workflow-ttl-workers
podCleanupWorkers int // --pod-cleanup-workers
cronWorkflowWorkers int // --cron-workflow-workers
workflowArchiveWorkers int // --workflow-archive-workers
burst int
qps float32
namespaced bool // --namespaced
managedNamespace string // --managed-namespace
executorPlugins bool
clientConfig clientcmd.ClientConfig
configMap string // --configmap
executorImage string // --executor-image
executorImagePullPolicy string // --executor-image-pull-policy
logLevel string // --loglevel
glogLevel int // --gloglevel
logFormat string // --log-format
workflowWorkers int // --workflow-workers
workflowTTLWorkers int // --workflow-ttl-workers
podCleanupWorkers int // --pod-cleanup-workers
cronWorkflowWorkers int // --cron-workflow-workers
workflowArchiveWorkers int // --workflow-archive-workers
burst int
qps float32
namespaced bool // --namespaced
managedNamespace string // --managed-namespace
executorPlugins bool
workflowLevelExecutorPlugins bool
)

command := cobra.Command{
Expand Down Expand Up @@ -113,8 +114,7 @@ func NewRootCommand() *cobra.Command {
if namespaced && managedNamespace == "" {
managedNamespace = namespace
}

wfController, err := controller.NewWorkflowController(ctx, config, kubeclientset, wfclientset, namespace, managedNamespace, executorImage, executorImagePullPolicy, logFormat, configMap, executorPlugins)
wfController, err := controller.NewWorkflowController(ctx, config, kubeclientset, wfclientset, namespace, managedNamespace, executorImage, executorImagePullPolicy, logFormat, configMap, executorPlugins, workflowLevelExecutorPlugins)
if err != nil {
return err
}
Expand Down Expand Up @@ -205,6 +205,8 @@ func NewRootCommand() *cobra.Command {
command.Flags().BoolVar(&namespaced, "namespaced", false, "run workflow-controller as namespaced mode")
command.Flags().StringVar(&managedNamespace, "managed-namespace", "", "namespace that workflow-controller watches, default to the installation namespace")
command.Flags().BoolVar(&executorPlugins, "executor-plugins", false, "enable executor plugins")
command.Flags().BoolVar(&workflowLevelExecutorPlugins, "workflow-level-executor-plugins", false, "enable workflow-level executor plugins")

ctx, log, err := cmdutil.ContextWithLogger(&command, logLevel, logFormat)
if err != nil {
logging.InitLogger().WithError(err).WithFatal().Error(command.Context(), "Failed to create workflow-controller logger")
Expand Down
15 changes: 12 additions & 3 deletions docs/executor_plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

## Configuration

Executor Plugins are disabled by default in the Workflow Controller.
To enable them, start the Controller with `ARGO_EXECUTOR_PLUGINS=true`.
For example:
Executor Plugins are disabled by default.
They can be enabled either globally via the Workflow Controller ConfigMap or per workflow.
Use the corresponding flags to enable them:
`ARGO_EXECUTOR_PLUGINS=true` - enables the use of Executor Plugins defined globally in the controller’s ConfigMap.
`ARGO_WORKFLOW_LEVEL_EXECUTOR_PLUGINS=true` - allows using Executor Plugin settings specified directly in the workflow spec. These settings take precedence over the global ones.
These two options are independent of each other: you can enable only the global plugins, only the workflow-level plugins, or both at the same time.

For example, to enable both modes in the Workflow Controller deployment:

```yaml
apiVersion: apps/v1
Expand All @@ -19,6 +24,8 @@ spec:
env:
- name: ARGO_EXECUTOR_PLUGINS
value: "true"
- name: ARGO_WORKFLOW_LEVEL_EXECUTOR_PLUGINS
value: "true"
```

When using the [Helm chart](https://github.com/argoproj/argo-helm/tree/master/charts/argo-workflows), add this to your `values.yaml`:
Expand All @@ -28,6 +35,8 @@ controller:
extraEnv:
- name: ARGO_EXECUTOR_PLUGINS
value: "true"
- name: ARGO_WORKFLOW_LEVEL_EXECUTOR_PLUGINS
value: "true"
```

### Example: A Simple Python Plugin
Expand Down
30 changes: 30 additions & 0 deletions docs/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,7 @@ WorkflowSpec is the specification of a Workflow.
|`dnsPolicy`|`string`|Set DNS policy for workflow pods. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.|
|`entrypoint`|`string`|Entrypoint is a template reference to the starting point of the io.argoproj.workflow.v1alpha1.|
|`executor`|[`ExecutorConfig`](#executorconfig)|Executor holds configurations of executor containers of the io.argoproj.workflow.v1alpha1.|
|`executorPlugins`|`Array<`[`ExecutorPlugin`](#executorplugin)`>`|Specifies executor plugins at the workflow level. This field is effective only when the ARGO_WORKFLOW_LEVEL_EXECUTOR_PLUGINS feature gate is enabled. If this field is present (even if empty), executor plugin settings from the controller ConfigMap are ignored. If this field is not set, the controller falls back to the ConfigMap configuration.|
|`hooks`|[`LifecycleHook`](#lifecyclehook)|Hooks holds the lifecycle hook which is invoked at lifecycle of step, irrespective of the success, failure, or error status of the primary step|
|`hostAliases`|`Array<`[`HostAlias`](#hostalias)`>`|_No description available_|
|`hostNetwork`|`boolean`|Host networking requested for this workflow pod. Default to false.|
Expand Down Expand Up @@ -1657,6 +1658,16 @@ ExecutorConfig holds configurations of an executor container.
|:----------:|:----------:|---------------|
|`serviceAccountName`|`string`|ServiceAccountName specifies the service account name of the executor container.|

## ExecutorPlugin

ExecutorPlugin describes workflow-level executor plugin

### Fields
| Field Name | Field Type | Description |
|:----------:|:----------:|---------------|
|`metadata`|[`ObjectMeta`](#objectmeta)|_No description available_|
|`spec`|[`ExecutorPluginSpec`](#executorpluginspec)|_No description available_|

## LifecycleHook

_No description available_
Expand Down Expand Up @@ -2510,6 +2521,15 @@ Parameter indicate a passed string parameter to a service template with an optio
|`value`|`string`|Value is the literal value to use for the parameter. If specified in the context of an input parameter, any passed values take precedence over the specified value|
|`valueFrom`|[`ValueFrom`](#valuefrom)|ValueFrom is the source for the output parameter's value|

## ExecutorPluginSpec

_No description available_

### Fields
| Field Name | Field Type | Description |
|:----------:|:----------:|---------------|
|`sidecar`|[`ExecutorPluginSidecar`](#executorpluginsidecar)|_No description available_|

## TemplateRef

TemplateRef is a reference of template resource.
Expand Down Expand Up @@ -3920,6 +3940,16 @@ ValueFrom describes a location in which to obtain the value to a parameter
|`path`|`string`|Path in the container to retrieve an output parameter value from in container templates|
|`supplied`|[`SuppliedValueFrom`](#suppliedvaluefrom)|Supplied value to be filled in directly, either through the CLI, API, etc.|

## ExecutorPluginSidecar

_No description available_

### Fields
| Field Name | Field Type | Description |
|:----------:|:----------:|---------------|
|`automountServiceAccountToken`|`boolean`|AutomountServiceAccount mounts the service account's token. The service account must have the same name as the plugin.|
|`container`|[`Container`](#container)|Container defines the Kubernetes container specification for the sidecar.|

## Counter

Counter is a Counter prometheus metric
Expand Down
Loading
Loading