Commit aab26f47 authored by Konstantinos Togias's avatar Konstantinos Togias
Browse files

Align TF-SDK actions and workload kind with Architecture

Use the proposed public action vocabulary and keep the Kubernetes surface limited to implemented actions.
parent e87be5bd
Loading
Loading
Loading
Loading
+9 −13
Changes for src/openop_tfsdk/contract/adapters/kubernetes.py: 9 added lines, 13 removed lines.
Original line number Diff line number Diff line
@@ -20,13 +20,13 @@ from openop_tfsdk.contract.execution_models import (
)
from openop_tfsdk.contract.models import SupportedAction

LIFECYCLE_CAPABILITY_KINDS = frozenset({"deploy_workload"})
LIFECYCLE_CAPABILITY_KINDS = frozenset({"workload"})

LIFECYCLE_ACTIONS = [
    SupportedAction.ACTIVATE_CAPABILITY,
    SupportedAction.UPDATE_CAPABILITY,
    SupportedAction.DEACTIVATE_CAPABILITY,
    SupportedAction.GET_CAPABILITY_RUNTIME_STATE,
    SupportedAction.ACTIVATE,
    SupportedAction.UPDATE,
    SupportedAction.TERMINATE,
    SupportedAction.READ_RUNTIME_STATE,
]

RUNTIME_KINDS = ["helm"]
@@ -46,7 +46,7 @@ class KubernetesCapabilityAdapter:
            return list(LIFECYCLE_ACTIONS), list(RUNTIME_KINDS)
        return [], []

    def activate_capability(self, request: CapabilityLifecycleRequest) -> CapabilityLifecycleResult:
    def activate(self, request: CapabilityLifecycleRequest) -> CapabilityLifecycleResult:
        unit = request.deployment_unit
        release_name = unit.deployment_unit_ref
        namespace = self._infrastructure.get("namespace", "default")
@@ -80,9 +80,7 @@ class KubernetesCapabilityAdapter:
            external_id=release_name,
        )

    def get_capability_runtime_state(
        self, request: CapabilityRuntimeStateRequest
    ) -> CapabilityRuntimeState:
    def read_runtime_state(self, request: CapabilityRuntimeStateRequest) -> CapabilityRuntimeState:
        release_name = request.external_id
        namespace = self._infrastructure.get("namespace", "default")

@@ -118,9 +116,7 @@ class KubernetesCapabilityAdapter:
            details={"helm_status": helm_status},
        )

    def deactivate_capability(
        self, request: CapabilityLifecycleRequest
    ) -> CapabilityLifecycleResult:
    def terminate(self, request: CapabilityLifecycleRequest) -> CapabilityLifecycleResult:
        release_name = request.external_id
        namespace = self._infrastructure.get("namespace", "default")

@@ -152,7 +148,7 @@ class KubernetesCapabilityAdapter:
            external_id=release_name,
        )

    def update_capability(self, request: CapabilityLifecycleRequest) -> CapabilityLifecycleResult:
    def update(self, request: CapabilityLifecycleRequest) -> CapabilityLifecycleResult:
        unit = request.deployment_unit
        release_name = request.external_id
        namespace = self._infrastructure.get("namespace", "default")
+2 −2
Changes for src/openop_tfsdk/contract/execution_models.py: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ Capability execution models of the SRM <=> TF-SDK contract (Sections 10-12).

Nesting: CapabilityLifecycleRequest -> ResolvedCapabilityTarget, DeploymentUnit
-> ComputeRequirements, Parameters. Most sub-fields are network/trust-oriented
and stay unset for a kubernetes deploy_workload request.
and stay unset for a Kubernetes workload request.
"""
from enum import Enum
from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network
@@ -193,7 +193,7 @@ class CapabilityLifecycleRequest(BaseModel):


class CapabilityLifecycleResult(BaseModel):
    """The normalized result of a capability activation, update or deactivation."""
    """The normalized result of a capability activation, update or termination."""

    operation_id: str

+6 −6
Changes for src/openop_tfsdk/contract/models.py: 6 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -25,11 +25,11 @@ class State(str, Enum):
class SupportedAction(str, Enum):
    """Actions a ControlPathBinding may declare support for."""

    ACTIVATE_CAPABILITY = "activate_capability"
    UPDATE_CAPABILITY = "update_capability"
    DEACTIVATE_CAPABILITY = "deactivate_capability"
    QUERY_CAPABILITY = "query_capability"
    GET_CAPABILITY_RUNTIME_STATE = "get_capability_runtime_state"
    ACTIVATE = "activate"
    UPDATE = "update"
    TERMINATE = "terminate"
    QUERY = "query"
    READ_RUNTIME_STATE = "read_runtime_state"


class ControlPathBinding(BaseModel):
@@ -54,7 +54,7 @@ class Capability(BaseModel):

    ref: str
    name: str
    kind: str  # deploy_workload | qod_session | ...
    kind: str  # workload | qod_session | ...
    state: State
    control_path_bindings: Optional[List[ControlPathBinding]] = None
    metadata: Optional[dict] = None
+1 −1
Changes for tests/contract/bootstrap_example.yaml: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ zones:

          - ref: deploy-workload
            name: Deploy Workload
            kind: deploy_workload
            kind: workload
            state: active

            control_path_bindings:
+22 −7
Changes for tests/contract/test_topology.py: 22 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ import os

import pytest

from openop_tfsdk.contract.adapters.kubernetes import KubernetesCapabilityAdapter
from openop_tfsdk.contract.interfaces import TopologyDiscoveryAdapter
from openop_tfsdk.contract.models import State, SupportedAction
from openop_tfsdk.contract.topology import BootstrapTopology
@@ -56,9 +57,7 @@ def test_get_capabilities_filters_by_parent_domain(topology):


def test_get_capabilities_filters_by_kind(topology):
    assert [c.kind for c in topology.get_capabilities(kind="deploy_workload")] == [
        "deploy_workload"
    ]
    assert [c.kind for c in topology.get_capabilities(kind="workload")] == ["workload"]


def test_bindings_resolve_to_their_control_path(topology):
@@ -79,14 +78,30 @@ def test_lifecycle_binding_gets_its_actions_from_the_adapter(topology):
    # The YAML declares neither field on this binding.
    binding = topology.get_control_path_bindings(capability_ref="deploy-workload")[0]
    assert binding.supported_actions == [
        SupportedAction.ACTIVATE_CAPABILITY,
        SupportedAction.UPDATE_CAPABILITY,
        SupportedAction.DEACTIVATE_CAPABILITY,
        SupportedAction.GET_CAPABILITY_RUNTIME_STATE,
        SupportedAction.ACTIVATE,
        SupportedAction.UPDATE,
        SupportedAction.TERMINATE,
        SupportedAction.READ_RUNTIME_STATE,
    ]
    assert binding.supported_runtime_kinds == ["helm"]


def test_advertised_actions_match_public_vocabulary_and_methods(topology):
    binding = topology.get_control_path_bindings(capability_ref="deploy-workload")[0]
    assert {action.value for action in SupportedAction} == {
        "activate",
        "update",
        "terminate",
        "query",
        "read_runtime_state",
    }
    assert all(
        callable(getattr(KubernetesCapabilityAdapter, action.value, None))
        for action in binding.supported_actions
    )
    assert KubernetesCapabilityAdapter.capability_surface("deploy_workload") == ([], [])


def test_query_binding_declares_nothing_kubernetes_does_not_execute(topology):
    # query_available_resources is not a kind KubernetesCapabilityAdapter executes.
    binding = topology.get_control_path_bindings(capability_ref="query-available-resources")[0]