Skip to content

Commit

Permalink
Merge branch 'main' into new-container-decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
flaviuvadan authored Jun 10, 2024
2 parents db04b42 + cc222ad commit 7b5ae85
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 123 deletions.
3 changes: 3 additions & 0 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ template: $CHANGES
name-template: v$RESOLVED_VERSION
tag-template: $RESOLVED_VERSION
categories:
- title: ℹ️ Information
labels:
- type:informational
- title: ⭐️ Enhancements
labels:
- type:enhancement
Expand Down
81 changes: 80 additions & 1 deletion docs/walk-through/authentication.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Authentication

The way you authenticate generally depends on your unique organization setup. If you submit workflows through Hera
The way you authenticate generally depends on your unique organization setup. You could either directly authenticate against the Argo server, or you handle authentication directly through the reverse proxy, or even both.

If you submit workflows through Hera
directly you have multiple ways to authenticate with the Argo server.

Note that the follow examples combine a global config with a workflow submission for illustration purposes. You can
Expand Down Expand Up @@ -148,6 +150,83 @@ global_config.token = K8sTokenGenerator("my-service-account")

# the workflow automatically creates a workflow service, which uses the global config
# host and token generator for authentication
with Workflow(
generate_name="test-",
entrypoint="c",
) as w:
Container(name="c", image="alpine:3.13", command=["sh", "-c", "echo hello world"])

w.create()
```

## Client Certificates

There are cases where your org might have client certificate authentication enabled which means that you'd have to present a client cert + key everytime you wish to access a UI or API.
In those cases you could either pass the certs on the global config or directly into the `WorkflowService`

### Workflow Service

```python
from hera.workflows import WorkflowsService, Workflow, Container

with Workflow(
generate_name="test-",
workflows_service=WorkflowsService(
host="https://my-argo-server.com",
token="Bearer abc123",
),
client_certs=("/path-to-client-cert","/path-to-client-key")
entrypoint="c",
) as w:
Container(name="c", image="alpine:3.13", command=["sh", "-c", "echo hello world"])

w.create()
```

## Global configuration

You can set a global configuration for Hera to inject the client certificates into the automatically created `WorkflowsService` object.
The global config token can take multiple types such as a `(str, str)` or `(Path, Path)` tuple or a function generating a `(str, str) or (Path, Path)`.

#### Simple `(str,str)`

```python
from hera.shared import global_config
from hera.workflows import Workflow, Container

global_config.host = "https://my-argo-server.com"
global_config.token = "abc-123" # this will be injected to all workflows' services for auth purposes!
global_config.client_certs = ("/path-to-client-cert","/path-to-client-key")
with Workflow(
generate_name="test-",
entrypoint="c",
) as w:
Container(name="c", image="alpine:3.13", command=["sh", "-c", "echo hello world"])

w.create()
```

#### A function that returns a `(str, str) or (Path, Path)` (`Callable[[], Union[Optional[Tuple[Path, Path]], Optional[Tuple[str, str]]]]`)

```python
from typing import Optional,Tuple
from pathlib import Path
from hera.shared import global_config
from hera.workflows import Workflow, Container


def get_certs() -> Optional[Tuple[str,str]]:
"""Generate or grab client certs for Hera.
This process can do anything and generate a token however you need it to"""
return ("/path-to-client-cert","/path-to-client-key")

def get_cert_paths() -> Optional[Tuple[Path, Path]]:
return (Path("/path-to-client-cert"), Path("/path-to-client-key"))


global_config.host = "https://my-argo-server.com"
global_config.token = get_certs # or get_cert_paths

with Workflow(
generate_name="test-",
entrypoint="c",
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ nav:
- Experimental Features:
- ... | flat | examples/workflows/experimental/*.md
- Miscellaneous Examples:
- ... | flat | examples/workflows/*.md
- ... | flat | examples/workflows/misc/*.md
- Use-Cases and Integrations:
- About: examples/about-use-cases.md
- ... | flat | examples/workflows/use-cases/*.md
Expand Down
228 changes: 114 additions & 114 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name = "hera" # project-name
# The version is automatically substituted by the CI
version = "0.0.0-dev"
description = "Hera is a Python framework for constructing and submitting Argo Workflows. The main goal of Hera is to make Argo Workflows more accessible by abstracting away some setup that is typically necessary for constructing Argo workflows."
authors = ["Flaviu Vadan <flaviu.vadan@dynotx.com>", "Sambhav Kothari <sambhavs.email@gmail.com>", "Elliot Gunton <elliotgunton@gmail.com>"]
maintainers = ["Flaviu Vadan <flaviu.vadan@dynotx.com>", "Sambhav Kothari <sambhavs.email@gmail.com>", "Elliot Gunton <elliotgunton@gmail.com>"]
authors = ["Flaviu Vadan <flaviuvadan@gmail.com>", "Sambhav Kothari <sambhavs.email@gmail.com>", "Elliot Gunton <elliotgunton@gmail.com>"]
maintainers = ["Flaviu Vadan <flaviuvadan@gmail.com>", "Sambhav Kothari <sambhavs.email@gmail.com>", "Elliot Gunton <elliotgunton@gmail.com>"]
license = "Apache-2.0"
readme = "README.md"
homepage = "https://github.com/argoproj-labs/hera"
Expand Down
7 changes: 5 additions & 2 deletions scripts/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ def __str__(self) -> str:
params={params},
headers={headers},
data={body},
verify=self.verify_ssl
verify=self.verify_ssl,
cert=self.client_certs,
)
if resp.ok:
Expand Down Expand Up @@ -406,7 +407,7 @@ def get_service_def() -> str:
from hera.{module}.models import {imports}
from hera.shared import global_config
from hera.exceptions import exception_from_server_response
from typing import Optional, cast
from typing import Optional, Tuple, cast
def valid_host_scheme(host: str) -> bool:
\"\"\"Validates the the given `host` starts with either `http` or `https`.\"\"\"
Expand All @@ -419,11 +420,13 @@ def __init__(
host: Optional[str] = None,
verify_ssl: Optional[bool] = None,
token: Optional[str] = None,
client_certs: Optional[Tuple[str, str]] = None,
namespace: Optional[str] = None,
) -> None:
\"\"\"{models_type} service constructor.\"\"\"
self.host = cast(str, host or global_config.host)
self.verify_ssl = verify_ssl if verify_ssl is not None else global_config.verify_ssl
self.client_certs = client_certs if client_certs is not None else global_config.client_certs
# some users reported in https://github.com/argoproj-labs/hera/issues/1016 that it can be a bit awkward for
# Hera to assume a `Bearer` prefix on behalf of users. Some might pass it and some might not. Therefore, Hera
Expand Down
28 changes: 27 additions & 1 deletion src/hera/events/service.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Interact with the REST service."""

# [DO NOT MODIFY] Auto-generated by `hera.scripts.service.py`
from typing import Optional, cast
from typing import Optional, Tuple, cast
from urllib.parse import urljoin

import requests
Expand Down Expand Up @@ -45,11 +45,13 @@ def __init__(
host: Optional[str] = None,
verify_ssl: Optional[bool] = None,
token: Optional[str] = None,
client_certs: Optional[Tuple[str, str]] = None,
namespace: Optional[str] = None,
) -> None:
"""Events service constructor."""
self.host = cast(str, host or global_config.host)
self.verify_ssl = verify_ssl if verify_ssl is not None else global_config.verify_ssl
self.client_certs = client_certs if client_certs is not None else global_config.client_certs

# some users reported in https://github.com/argoproj-labs/hera/issues/1016 that it can be a bit awkward for
# Hera to assume a `Bearer` prefix on behalf of users. Some might pass it and some might not. Therefore, Hera
Expand Down Expand Up @@ -106,6 +108,7 @@ def list_event_sources(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -126,6 +129,7 @@ def create_event_source(self, req: CreateEventSourceRequest, namespace: Optional
exclude_none=True, by_alias=True, skip_defaults=True, exclude_unset=True, exclude_defaults=True
),
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -144,6 +148,7 @@ def get_event_source(self, name: str, namespace: Optional[str] = None) -> EventS
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -166,6 +171,7 @@ def update_event_source(
exclude_none=True, by_alias=True, skip_defaults=True, exclude_unset=True, exclude_defaults=True
),
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -201,6 +207,7 @@ def delete_event_source(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -221,6 +228,7 @@ def receive_event(self, discriminator: str, req: Item, namespace: Optional[str]
exclude_none=True, by_alias=True, skip_defaults=True, exclude_unset=True, exclude_defaults=True
),
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -237,6 +245,7 @@ def get_info(self) -> InfoResponse:
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -277,6 +286,7 @@ def list_sensors(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -297,6 +307,7 @@ def create_sensor(self, req: CreateSensorRequest, namespace: Optional[str] = Non
exclude_none=True, by_alias=True, skip_defaults=True, exclude_unset=True, exclude_defaults=True
),
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -315,6 +326,7 @@ def get_sensor(self, name: str, namespace: Optional[str] = None, resource_versio
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -335,6 +347,7 @@ def update_sensor(self, name: str, req: UpdateSensorRequest, namespace: Optional
exclude_none=True, by_alias=True, skip_defaults=True, exclude_unset=True, exclude_defaults=True
),
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -370,6 +383,7 @@ def delete_sensor(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -410,6 +424,7 @@ def watch_event_sources(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -460,6 +475,7 @@ def event_sources_logs(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -500,6 +516,7 @@ def watch_events(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -540,6 +557,7 @@ def watch_sensors(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -588,6 +606,7 @@ def sensors_logs(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -604,6 +623,7 @@ def get_user_info(self) -> GetUserInfoResponse:
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -620,6 +640,7 @@ def get_version(self) -> Version:
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down Expand Up @@ -654,6 +675,7 @@ def get_artifact_file(
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -672,6 +694,7 @@ def get_output_artifact_by_uid(self, uid: str, node_id: str, artifact_name: str)
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -693,6 +716,7 @@ def get_output_artifact(self, name: str, node_id: str, artifact_name: str, names
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -711,6 +735,7 @@ def get_input_artifact_by_uid(self, uid: str, node_id: str, artifact_name: str)
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand All @@ -732,6 +757,7 @@ def get_input_artifact(self, name: str, node_id: str, artifact_name: str, namesp
headers={"Authorization": self.token},
data=None,
verify=self.verify_ssl,
cert=self.client_certs,
)

if resp.ok:
Expand Down
Loading

0 comments on commit 7b5ae85

Please sign in to comment.