Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8f8e768
feat: Initial commit
albertoperdomo2 Apr 13, 2026
8ad219d
refactor: move llm_d config and phases
albertoperdomo2 Apr 15, 2026
7f820e0
feat: Add llm_d model cache
albertoperdomo2 Apr 16, 2026
71e1d95
fix: Lint after rebase
albertoperdomo2 Apr 16, 2026
1702e5b
refactor: Separate llm_d scheduler profiles
albertoperdomo2 Apr 20, 2026
e81e78e
refactor: Rename llm_d capture toolbox
albertoperdomo2 Apr 20, 2026
38aeb72
fix: Harden llm_d runtime command handling
albertoperdomo2 Apr 20, 2026
6393dc4
fix: Make NFD prepare idempotent
albertoperdomo2 Apr 21, 2026
461bc91
fix: Run llm_d smoke in helper job
albertoperdomo2 Apr 21, 2026
69a445f
feat: Add llm_d scheduler profiles
albertoperdomo2 Apr 21, 2026
f134a01
refactor: Split llm_d runtime helpers
albertoperdomo2 May 3, 2026
486bfc6
refactor: Add llm_d phase input boundary
albertoperdomo2 May 3, 2026
6d9c8c9
refactor: Convert llm_d cleanup and model-cache phases to DSL tasks
albertoperdomo2 May 3, 2026
605b519
refactor: Inline llm_d prepare and test task logic
albertoperdomo2 May 3, 2026
c35abd5
chore: Reorder tests within project
albertoperdomo2 May 3, 2026
8cc21e1
fix: Install Forge dependencies for pytest CI
albertoperdomo2 May 4, 2026
bb81123
refactor: Move llm_d shared runtime out of orchestration
albertoperdomo2 May 5, 2026
c532d91
refactor: Normalize llm_d project configuration layout
albertoperdomo2 May 5, 2026
9846855
test: Align llm_d runtime coverage with explicit inputs
albertoperdomo2 May 5, 2026
0ccb78e
refactor: Deduplicate DSL toolbox path helpers
albertoperdomo2 May 5, 2026
bb02000
docs: Refresh llm_d layout references
albertoperdomo2 May 5, 2026
2c9e527
chore: Run linter locally
albertoperdomo2 May 5, 2026
55e2242
refactor: Align llm_d runtime config with Forge overrides
albertoperdomo2 May 13, 2026
1403ce2
refactor: Split llm_d flows into toolbox commands
albertoperdomo2 May 17, 2026
bc7d623
Fix llm_d live prepare flow
albertoperdomo2 May 18, 2026
dcfdf68
feat: Wire PR args
albertoperdomo2 May 18, 2026
b6d77c2
fix: Add llm_d fournos resolver command
albertoperdomo2 May 18, 2026
985d69b
fix: Add Vaults to llm_d project
albertoperdomo2 May 18, 2026
370014a
chore: Minor fixes
albertoperdomo2 May 18, 2026
29374ac
Merge branch 'main' into feat/downstream-llm-d
albertoperdomo2 May 18, 2026
ad8cee9
fix: Redirect llm_d namespace event capture
albertoperdomo2 May 18, 2026
e8ebea5
refactor: Simplify llm_d toolbox interfaces
albertoperdomo2 May 18, 2026
da1005a
Merge branch 'feat/downstream-llm-d' of github.com:albertoperdomo2/fo…
albertoperdomo2 May 18, 2026
609be4a
fix: Add llm_d caliper export config
albertoperdomo2 May 18, 2026
cf23cfd
fix: Initialize llm_d vaults for export
albertoperdomo2 May 18, 2026
a037efa
refactor: Inline llm_d toolbox arguments
albertoperdomo2 May 18, 2026
2f5edf0
refactor: Flatten llm_d test runtime flow
albertoperdomo2 May 19, 2026
31313e8
refactor: Remove abstract llm_d toolbox commands
albertoperdomo2 May 19, 2026
06cfb68
fix: CI overrides win
albertoperdomo2 May 19, 2026
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
6 changes: 3 additions & 3 deletions .github/workflows/test_toolbox_dsl.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Unit tests for projects/core/dsl (task decorators, execute_tasks, failure/always/skip).
name: Toolbox DSL tests
# Python tests for repo-managed suites discovered via pyproject testpaths.
name: Python test suites

on:
pull_request:
Expand Down Expand Up @@ -31,7 +31,7 @@ jobs:
python -m pip install --upgrade pip
python -m pip install -e .[testing]

- name: Run projects/core/tests
- name: Run pytest suites
run: |
set -o errexit
# Tree + docstrings (what is being tested), then execute with one line per test + result.
Expand Down
335 changes: 335 additions & 0 deletions projects/cluster/toolbox/cluster_deploy_operator/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
#!/usr/bin/env python3

from __future__ import annotations

import json
import logging

from projects.core.dsl import always, execute_tasks, retry, shell, task, template, toolbox

logger = logging.getLogger("DSL")


def run(
package_name: str,
target_namespace: str,
source_name: str,
channel: str,
*,
source_namespace: str = "openshift-marketplace",
wait_timeout_seconds: int = 900,
installplan_approval: str = "Automatic",
display_name: str = "",
) -> int:
"""
Deploy an OLM operator and wait for its CSV to succeed.

Args:
package_name: Operator package/subscription name
target_namespace: Namespace where the operator will be installed
source_name: CatalogSource name providing the operator
channel: Subscription channel to use
source_namespace: CatalogSource namespace
wait_timeout_seconds: Maximum time to wait for readiness
installplan_approval: InstallPlan approval mode
display_name: Optional human-friendly name used in logs
"""

execute_tasks(locals())
return 0


@task
def setup_directories(args, ctx):
"""Create command source and artifact directories"""

shell.mkdir("src")
shell.mkdir("artifacts")
ctx.display_name = args.display_name or args.package_name
return f"Prepared directories for {ctx.display_name}"


@task
def validate_parameters(args, ctx):
"""Validate command parameters"""

if not args.package_name:
raise ValueError("package_name is required")
if not args.target_namespace:
raise ValueError("target_namespace is required")
if not args.source_name:
raise ValueError("source_name is required")
if not args.channel:
raise ValueError("channel is required")
if args.installplan_approval not in {"Automatic", "Manual"}:
raise ValueError("installplan_approval must be either 'Automatic' or 'Manual'")

return (
f"Validated deployment parameters for {ctx.display_name} "
f"from {args.source_name}/{args.source_namespace}"
)


@retry(attempts=60, delay=15)
@task
def wait_for_catalog_source_ready(args, ctx):
"""Wait for the CatalogSource to report READY"""

result = shell.run(
"oc get catalogsource "
f"{args.source_name} -n {args.source_namespace} "
"-o jsonpath='{.status.connectionState.lastObservedState}'",
check=False,
log_stdout=False,
)
if not result.success:
return False

state = result.stdout.strip()
if state == "READY":
return f"CatalogSource {args.source_name} is READY"
return False


@retry(attempts=60, delay=15)
@task
def wait_for_package_manifest(args, ctx):
"""Wait for the operator PackageManifest to become available"""

result = shell.run(
f"oc get packagemanifest {args.package_name} -n {args.source_namespace} -o json",
check=False,
log_stdout=False,
)
if not result.success:
return False

ctx.package_manifest = json.loads(result.stdout)
return f"PackageManifest {args.package_name} is available"


@task
def render_namespace_manifest(args, ctx):
"""Render the target namespace manifest"""

ctx.namespace_manifest_file = (
args.artifact_dir / "src" / f"{args.target_namespace}-namespace.yaml"
)
template.render_template_to_file("namespace.yaml.j2", ctx.namespace_manifest_file)
return f"Rendered namespace manifest for {args.target_namespace}"


@task
def apply_namespace(args, ctx):
"""Apply the target namespace manifest"""

shell.run(f"oc apply -f {ctx.namespace_manifest_file}")
return f"Ensured namespace {args.target_namespace}"


@task
def render_operator_group_manifest(args, ctx):
"""Render the OperatorGroup manifest, unless a suitable one already exists"""

result = shell.run(
f"oc get operatorgroup -n {args.target_namespace} -o json",
check=False,
log_stdout=False,
)
if result.success:
operator_groups = json.loads(result.stdout).get("items", [])
for operator_group in operator_groups:
spec = operator_group.get("spec", {})
target_namespaces = spec.get("targetNamespaces", [])
if not target_namespaces or args.target_namespace in target_namespaces:
ctx.operator_group_manifest_file = None
ctx.operator_group_name = operator_group["metadata"]["name"]
return (
f"Reusing existing OperatorGroup {ctx.operator_group_name} "
f"in {args.target_namespace}"
)

if operator_groups:
names = ", ".join(
operator_group["metadata"]["name"] for operator_group in operator_groups
)
raise RuntimeError(
f"Namespace {args.target_namespace} already has OperatorGroups "
f"that do not target it: {names}"
)

ctx.operator_group_manifest_file = (
args.artifact_dir / "src" / f"{args.package_name}-operatorgroup.yaml"
)
template.render_template_to_file("operator_group.yaml.j2", ctx.operator_group_manifest_file)
return f"Rendered OperatorGroup manifest for {args.package_name}"


@task
def apply_operator_group(args, ctx):
"""Apply the OperatorGroup manifest"""

if ctx.operator_group_manifest_file is None:
return f"Using existing OperatorGroup {ctx.operator_group_name}"

shell.run(f"oc apply -f {ctx.operator_group_manifest_file}")
return f"Ensured OperatorGroup in {args.target_namespace}"


@task
def render_subscription_manifest(args, ctx):
"""Render the Subscription manifest"""

ctx.subscription_manifest_file = (
args.artifact_dir / "src" / f"{args.package_name}-subscription.yaml"
)
template.render_template_to_file("subscription.yaml.j2", ctx.subscription_manifest_file)
return f"Rendered Subscription manifest for {args.package_name}"


@task
def apply_subscription(args, ctx):
"""Apply the Subscription manifest"""

shell.run(f"oc apply -f {ctx.subscription_manifest_file}")
return f"Applied Subscription for {ctx.display_name}"


@retry(attempts=60, delay=15)
@task
def wait_for_csv_ready(args, ctx):
"""Wait for the installed CSV to reach Succeeded phase"""

result = shell.run(
"oc get csv "
f"-n {args.target_namespace} "
f"-l operators.coreos.com/{args.package_name}.{args.target_namespace} "
"-o json",
check=False,
log_stdout=False,
)
if not result.success:
return False

payload = json.loads(result.stdout)
items = payload.get("items", [])
if not items:
return False

csv = items[0]
ctx.csv_name = csv["metadata"]["name"]
phase = csv.get("status", {}).get("phase")
if phase == "Succeeded":
return f"CSV {ctx.csv_name} succeeded"
if phase in {"Failed", "Replacing"}:
logger.info("CSV %s currently in phase %s", ctx.csv_name, phase)
return False


@always
@task
def capture_catalog_source(args, ctx):
"""Capture CatalogSource YAML for diagnostics"""

shell.run(
f"oc get catalogsource {args.source_name} -n {args.source_namespace} -o yaml",
stdout_dest=args.artifact_dir / "artifacts" / "catalogsource.yaml",
check=False,
)
return "Captured CatalogSource state"


@always
@task
def capture_package_manifest(args, ctx):
"""Capture PackageManifest YAML and JSON"""

shell.run(
f"oc get packagemanifest {args.package_name} -n {args.source_namespace} -o yaml",
stdout_dest=args.artifact_dir / "artifacts" / "packagemanifest.yaml",
check=False,
)
shell.run(
f"oc get packagemanifest {args.package_name} -n {args.source_namespace} -o json",
stdout_dest=args.artifact_dir / "artifacts" / "packagemanifest.json",
check=False,
)
return "Captured PackageManifest state"


@always
@task
def capture_operator_group(args, ctx):
"""Capture OperatorGroup YAML"""

shell.run(
f"oc get operatorgroup -n {args.target_namespace} -o yaml",
stdout_dest=args.artifact_dir / "artifacts" / "operatorgroup.yaml",
check=False,
)
return "Captured OperatorGroup state"


@always
@task
def capture_subscription(args, ctx):
"""Capture Subscription YAML"""

shell.run(
f"oc get subscription {args.package_name} -n {args.target_namespace} -o yaml",
stdout_dest=args.artifact_dir / "artifacts" / "subscription.yaml",
check=False,
)
return "Captured Subscription state"


@always
@task
def capture_csv(args, ctx):
"""Capture installed CSV YAML when known"""

csv_name = getattr(ctx, "csv_name", "")
if not csv_name:
result = shell.run(
"oc get csv "
f"-n {args.target_namespace} "
f"-l operators.coreos.com/{args.package_name}.{args.target_namespace} "
"-o jsonpath='{.items[0].metadata.name}'",
check=False,
log_stdout=False,
)
csv_name = result.stdout.strip()
if not csv_name:
return "No CSV found to capture"

shell.run(
f"oc get csv {csv_name} -n {args.target_namespace} -o yaml",
stdout_dest=args.artifact_dir / "artifacts" / "csv.yaml",
check=False,
)
return f"Captured CSV {csv_name}"


@always
@task
def capture_target_namespace_pods(args, ctx):
"""Capture pods from the operator target namespace"""

shell.run(
f"oc get pods -n {args.target_namespace} -o wide",
stdout_dest=args.artifact_dir / "artifacts" / "pods.status",
check=False,
)
shell.run(
f"oc get pods -n {args.target_namespace} -o yaml",
stdout_dest=args.artifact_dir / "artifacts" / "pods.yaml",
check=False,
)
return "Captured target namespace pods"


main = toolbox.create_toolbox_main(run)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: {{ args.target_namespace }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: {{ args.package_name }}
namespace: {{ args.target_namespace }}
spec:
targetNamespaces:
- {{ args.target_namespace }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: {{ args.package_name }}
namespace: {{ args.target_namespace }}
spec:
channel: {{ args.channel }}
installPlanApproval: {{ args.installplan_approval }}
name: {{ args.package_name }}
source: {{ args.source_name }}
sourceNamespace: {{ args.source_namespace }}
Loading
Loading