|
2 | 2 |
|
3 | 3 | ## Current Status |
4 | 4 |
|
5 | | -**Last updated:** 2026-01-13 |
6 | | -**Current phase:** REST API Enhancement - POST /scenarios/globals COMPLETED |
| 5 | +**Last updated:** 2026-01-14 |
| 6 | +**Current phase:** Scenario Job Management - COMPLETED |
7 | 7 |
|
8 | 8 | ### Completed |
9 | 9 | - Project scaffolding with Kubebuilder |
|
80 | 80 | - ✅ Returns 404 if global environment not found |
81 | 81 | - ✅ Type fields converted to strings (not enum integers) |
82 | 82 | - ✅ Handler registered at POST /scenarios/globals/{scenario_name} |
| 83 | +- **Scenario Job Management endpoints completed:** |
| 84 | + - ✅ POST /scenarios/run - Create and start scenario job |
| 85 | + - ✅ GET /scenarios/run/{jobId} - Get job status |
| 86 | + - ✅ GET /scenarios/run/{jobId}/logs - Stream logs (stub, requires clientset) |
| 87 | + - ✅ GET /scenarios/run - List all jobs with filtering |
| 88 | + - ✅ DELETE /scenarios/run/{jobId} - Stop and delete job |
| 89 | + - ✅ Router handler for endpoint dispatching |
| 90 | + - ✅ Complete kubeconfig retrieval and mounting |
| 91 | + - ✅ File mounts via ConfigMaps (base64 encoded) |
| 92 | + - ✅ Private registry support with ImagePullSecrets |
| 93 | + - ✅ Pod lifecycle management with cleanup |
| 94 | + - ✅ RBAC permissions updated |
| 95 | +- **Code refactoring completed:** |
| 96 | + - ✅ Extracted getKubeconfigFromTarget() helper function |
| 97 | + - ✅ Refactored GET /nodes to use helper |
| 98 | + - ✅ Refactored POST /scenarios/run to use helper |
| 99 | + - ✅ Eliminated ~130 lines of duplicated code |
83 | 100 |
|
84 | 101 | ### In Progress |
85 | 102 | - None |
@@ -837,6 +854,159 @@ curl -X POST http://localhost:8080/scenarios/globals/pod-scenarios \ |
837 | 854 | } |
838 | 855 | ``` |
839 | 856 |
|
| 857 | +### Phase 12: Scenario Job Management - /scenarios/run Endpoints ✅ |
| 858 | +**Status:** COMPLETED |
| 859 | + |
| 860 | +1. ✅ Type Definitions (internal/api/types.go) |
| 861 | + - Created `FileMount` struct for user file uploads |
| 862 | + - Created `ScenarioRunRequest` with embedded `ScenariosRequest` |
| 863 | + - Created `ScenarioRunResponse` for job creation |
| 864 | + - Created `JobStatusResponse` with targetId, clusterName metadata |
| 865 | + - Created `JobsListResponse` for listing jobs |
| 866 | + |
| 867 | +2. ✅ POST /scenarios/run Implementation (internal/api/handlers.go) |
| 868 | + - Validates required fields: targetId, clusterName, scenarioImage, scenarioName |
| 869 | + - Uses `getKubeconfigFromTarget()` helper to retrieve kubeconfig |
| 870 | + - Creates ConfigMap for kubeconfig (decoded from base64) |
| 871 | + - Creates ConfigMaps for user-provided files (base64 decoded) |
| 872 | + - Supports private registry with ImagePullSecret creation |
| 873 | + - Creates pod with: |
| 874 | + - RestartPolicy: Never (one-time execution) |
| 875 | + - Labels: app, krkn-job-id, krkn-scenario-name, krkn-target-id, krkn-cluster-name |
| 876 | + - Environment variables from request |
| 877 | + - Volume mounts for kubeconfig and user files |
| 878 | + - ImagePullSecrets if registry credentials provided |
| 879 | + - Returns 201 Created with jobId, status "Pending", podName |
| 880 | + - Complete cleanup on error (deletes created ConfigMaps/Secrets) |
| 881 | + |
| 882 | +3. ✅ GET /scenarios/run/{jobId} Implementation |
| 883 | + - Finds pod by label `krkn-job-id` |
| 884 | + - Maps pod phase to job status |
| 885 | + - Extracts metadata from pod labels |
| 886 | + - Returns timestamps (startTime, completionTime) |
| 887 | + - Returns error messages for failed jobs |
| 888 | + |
| 889 | +4. ✅ GET /scenarios/run/{jobId}/logs Implementation (STUB) |
| 890 | + - Endpoint registered and routed correctly |
| 891 | + - Returns 501 Not Implemented |
| 892 | + - TODO: Requires Kubernetes clientset integration for actual log streaming |
| 893 | + - Query parameter parsing ready (follow, timestamps, tailLines) |
| 894 | + |
| 895 | +5. ✅ GET /scenarios/run Implementation |
| 896 | + - Lists all pods with label `app=krkn-scenario` |
| 897 | + - Supports filtering by: status, scenarioName, targetId, clusterName |
| 898 | + - Returns array of JobStatusResponse |
| 899 | + - Includes timestamps and metadata for each job |
| 900 | + |
| 901 | +6. ✅ DELETE /scenarios/run/{jobId} Implementation |
| 902 | + - Finds and deletes pod with 5 second grace period |
| 903 | + - Cleanup associated ConfigMaps (by label `krkn-job-id`) |
| 904 | + - Cleanup associated Secrets (ImagePullSecrets) |
| 905 | + - Returns status "Stopped" with success message |
| 906 | + |
| 907 | +7. ✅ Router Handler (ScenariosRunRouter) |
| 908 | + - Dispatches requests based on path and method |
| 909 | + - POST /scenarios/run → PostScenarioRun |
| 910 | + - GET /scenarios/run → ListScenarioRuns |
| 911 | + - GET /scenarios/run/{jobId} → GetScenarioRunStatus |
| 912 | + - GET /scenarios/run/{jobId}/logs → GetScenarioRunLogs |
| 913 | + - DELETE /scenarios/run/{jobId} → DeleteScenarioRun |
| 914 | + - Returns 405 Method Not Allowed for invalid methods |
| 915 | + |
| 916 | +8. ✅ RBAC Updates (config/rbac/role.yaml) |
| 917 | + - pods: added create, delete verbs |
| 918 | + - pods/log: added get verb |
| 919 | + - configmaps: added get, list, create, delete verbs |
| 920 | + - secrets: added create, delete verbs |
| 921 | + |
| 922 | +9. ✅ Build Verification |
| 923 | + - Successful compilation with no errors |
| 924 | + - All handlers properly integrated |
| 925 | + - Routes registered correctly |
| 926 | + |
| 927 | +**Implementation Highlights:** |
| 928 | +- **Pod naming**: `krkn-job-{jobId}` |
| 929 | +- **ConfigMap naming**: `krkn-job-{jobId}-kubeconfig`, `krkn-job-{jobId}-file-{sanitized-name}` |
| 930 | +- **Default kubeconfig path**: `/home/krkn/.kube/config` (configurable) |
| 931 | +- **Error handling**: Comprehensive cleanup on failures |
| 932 | +- **Label-based tracking**: No CRD required, uses pod labels |
| 933 | +- **Private registry**: Full support with ImagePullSecret creation |
| 934 | + |
| 935 | +**Request Example:** |
| 936 | +```json |
| 937 | +{ |
| 938 | + "targetId": "550e8400-e29b-41d4-a716-446655440000", |
| 939 | + "clusterName": "my-cluster-1", |
| 940 | + "scenarioImage": "quay.io/krkn-chaos/krkn-hub:pod-scenarios", |
| 941 | + "scenarioName": "pod-scenarios", |
| 942 | + "kubeconfigPath": "/home/krkn/.kube/config", |
| 943 | + "environment": { |
| 944 | + "NAMESPACE": "default", |
| 945 | + "LABEL_SELECTOR": "app=myapp" |
| 946 | + }, |
| 947 | + "files": [ |
| 948 | + { |
| 949 | + "name": "config.yaml", |
| 950 | + "content": "base64-encoded-content", |
| 951 | + "mountPath": "/config/scenario.yaml" |
| 952 | + } |
| 953 | + ] |
| 954 | +} |
| 955 | +``` |
| 956 | + |
| 957 | +**Response Example:** |
| 958 | +```json |
| 959 | +{ |
| 960 | + "jobId": "generated-uuid", |
| 961 | + "status": "Pending", |
| 962 | + "podName": "krkn-job-generated-uuid" |
| 963 | +} |
| 964 | +``` |
| 965 | + |
| 966 | +### Code Refactoring: getKubeconfigFromTarget() Helper ✅ |
| 967 | +**Status:** COMPLETED |
| 968 | + |
| 969 | +**Problem:** Kubeconfig retrieval logic was duplicated in GET /nodes and POST /scenarios/run (~130 lines total) |
| 970 | + |
| 971 | +**Solution:** Extracted common helper function `getKubeconfigFromTarget(ctx, targetId, clusterName)` |
| 972 | + |
| 973 | +**Location:** internal/api/handlers.go:275-318 |
| 974 | + |
| 975 | +**Functionality:** |
| 976 | +1. Fetches secret named `targetId` from operator namespace |
| 977 | +2. Parses `managed-clusters` JSON from secret data |
| 978 | +3. Navigates structure: `["krkn-operator-acm"][clusterName]["kubeconfig"]` |
| 979 | +4. Returns base64-encoded kubeconfig string |
| 980 | +5. Returns descriptive errors for all failure cases |
| 981 | + |
| 982 | +**Refactored Endpoints:** |
| 983 | +1. GET /nodes (lines ~137-156): Replaced ~65 lines with helper call |
| 984 | +2. POST /scenarios/run (lines ~820-838): Replaced ~70 lines with helper call |
| 985 | + |
| 986 | +**Benefits:** |
| 987 | +- **DRY Principle**: Single source of truth for kubeconfig retrieval |
| 988 | +- **Maintainability**: Changes only needed in one place |
| 989 | +- **Consistency**: Identical error handling across endpoints |
| 990 | +- **Testability**: Helper can be unit tested independently |
| 991 | +- **Code reduction**: ~130 lines eliminated |
| 992 | + |
| 993 | +**Before:** |
| 994 | +```go |
| 995 | +// Duplicated in GET /nodes and POST /scenarios/run |
| 996 | +var secret corev1.Secret |
| 997 | +err := h.client.Get(ctx, ...) |
| 998 | +// ... 60+ lines of identical code ... |
| 999 | +``` |
| 1000 | + |
| 1001 | +**After:** |
| 1002 | +```go |
| 1003 | +// Both endpoints now use: |
| 1004 | +kubeconfigBase64, err := h.getKubeconfigFromTarget(ctx, targetId, clusterName) |
| 1005 | +if err != nil { |
| 1006 | + // Error handling |
| 1007 | +} |
| 1008 | +``` |
| 1009 | + |
840 | 1010 | ## Technical Notes |
841 | 1011 |
|
842 | 1012 | ### KrknTargetRequest Structure |
@@ -931,12 +1101,19 @@ type KrknTargetRequestStatus struct { |
931 | 1101 | 9. ✅ Implement POST /scenarios endpoint with krknctl integration |
932 | 1102 | 10. ✅ Implement POST /scenarios/detail/{scenario_name} endpoint |
933 | 1103 | 11. ✅ Implement POST /scenarios/globals endpoint |
934 | | -12. Create API documentation (OpenAPI/Swagger spec) |
935 | | -13. Add additional endpoints as requirements evolve |
936 | | -14. Implement controller logic for KrknTargetRequest |
| 1104 | +12. ✅ Implement Scenario Job Management (/scenarios/run endpoints) |
| 1105 | +13. ✅ Code refactoring - extract getKubeconfigFromTarget() helper |
| 1106 | +14. Complete GET /scenarios/run/{jobId}/logs endpoint (requires Kubernetes clientset) |
| 1107 | +15. Create API documentation (OpenAPI/Swagger spec) |
| 1108 | +16. Add additional endpoints as requirements evolve |
| 1109 | +17. Implement controller logic for KrknTargetRequest |
937 | 1110 |
|
938 | 1111 | ## Future Work (Not in Current Scope) |
939 | 1112 |
|
| 1113 | +- Complete log streaming implementation for GET /scenarios/run/{jobId}/logs |
| 1114 | + - Requires Kubernetes clientset integration (rest.Config) |
| 1115 | + - Need to add clientset to Handler struct |
| 1116 | + - Implement actual streaming with io.Copy from pod logs API |
940 | 1117 | - Controller implementation for KrknTargetRequest |
941 | 1118 | - Controller implementation for KrknOperatorTargetProvider |
942 | 1119 | - Migration from environment variable to ConfigMap for namespace configuration |
|
0 commit comments