{"id":36753814,"url":"https://github.com/openshift-hyperfleet/status-reporter","last_synced_at":"2026-01-12T12:47:41.445Z","repository":{"id":329050143,"uuid":"1115052178","full_name":"openshift-hyperfleet/status-reporter","owner":"openshift-hyperfleet","description":"A reusable Kubernetes sidecar container designed to monitor adapter execution results and automatically update the parent Kubernetes Job status. This component provides a standardized way for adapters or validation containers to report outcomes without modifying their core logic. ","archived":false,"fork":false,"pushed_at":"2025-12-17T02:23:50.000Z","size":57,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-20T16:20:24.823Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openshift-hyperfleet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-12T09:17:08.000Z","updated_at":"2025-12-17T02:23:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/openshift-hyperfleet/status-reporter","commit_stats":null,"previous_names":["openshift-hyperfleet/status-reporter"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/openshift-hyperfleet/status-reporter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openshift-hyperfleet%2Fstatus-reporter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openshift-hyperfleet%2Fstatus-reporter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openshift-hyperfleet%2Fstatus-reporter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openshift-hyperfleet%2Fstatus-reporter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openshift-hyperfleet","download_url":"https://codeload.github.com/openshift-hyperfleet/status-reporter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openshift-hyperfleet%2Fstatus-reporter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338983,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-12T12:47:40.841Z","updated_at":"2026-01-12T12:47:41.440Z","avatar_url":"https://github.com/openshift-hyperfleet.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Status Reporter\n\nA **cloud-agnostic**, **reusable** Kubernetes sidecar container that monitors adapter operation results and updates Kubernetes Job status.\n\n## Overview\n\nThe status reporter is a production-ready Kubernetes sidecar container that works with any adapter container (validation, DNS, pull secret, etc.) that follows the defined result contract. It provides robust monitoring and status reporting capabilities for Kubernetes Jobs.\n\n**Key Features:**\n- Monitors adapter container execution via file polling and container state watching\n- Handles various failure scenarios (OOMKilled, crashes, timeouts, invalid results)\n- Updates Kubernetes Job status with detailed condition information\n- Zero-dependency on adapter implementation - uses simple JSON contract\n- Cloud-agnostic design - works with any Kubernetes environment\n\n## Adapter Contract\n\nThe status reporter works with any adapter container that follows this simple JSON contract:\n\n1. **Result File Requirements:**\n    - **Location:** Write results to the result file (configurable via `RESULTS_PATH` env var)\n    - **Format:** Valid JSON file (max size: 1MB)\n    - **Timing:** Must be written before the adapter container exits or within the configured timeout\n\n2. **JSON Schema:**\n   ```json\n   {\n     \"status\": \"success\",           // Required: \"success\" or \"failure\"\n     \"reason\": \"AllChecksPassed\",   // Required: Machine-readable identifier (max 128 chars)\n     \"message\": \"All validation checks passed successfully\",  // Required: Human-readable description (max 1024 chars)\n     \"details\": {                   // Optional: Adapter-specific data (any valid JSON), this information will not be reflected in k8s Job Status\n       \"checks_run\": 5,\n       \"duration_ms\": 1234\n     }\n   }\n   ```\n\n3. **Field Validation:**\n    - `status`: Must be exactly `\"success\"` or `\"failure\"` (case-sensitive)\n    - `reason`: Trimmed and truncated to 128 characters. Defaults to `\"NoReasonProvided\"` if empty/missing\n    - `message`: Trimmed and truncated to 1024 characters. Defaults to `\"No message provided\"` if empty/missing\n    - `details`: Optional JSON object containing any adapter-specific information\n\n4. **Examples:**\n\n   **Success result:**\n\n   Adapter writes to the result file:\n   ```json\n   {\n     \"status\": \"success\",\n     \"reason\": \"ValidationPassed\",\n     \"message\": \"GCP environment validated successfully\"\n   }\n   ```\n\n   Resulting Kubernetes Job status:\n   ```yaml\n   status:\n     conditions:\n     - type: Available\n       status: \"True\"\n       reason: ValidationPassed\n       message: GCP environment validated successfully\n       lastTransitionTime: \"2024-01-15T10:30:00Z\"\n   ```\n\n   **Failure result with details:**\n\n   Adapter writes to the result file:\n   ```json\n   {\n     \"status\": \"failure\",\n     \"reason\": \"MissingPermissions\",\n     \"message\": \"Service account lacks required IAM permissions\",\n     \"details\": {\n       \"missing_permissions\": [\"compute.instances.list\", \"iam.serviceAccounts.get\"],\n       \"service_account\": \"my-sa@project.iam.gserviceaccount.com\"\n     }\n   }\n   ```\n\n   Resulting Kubernetes Job status:\n   ```yaml\n   status:\n     conditions:\n     - type: Available\n       status: \"False\"\n       reason: MissingPermissions\n       message: Service account lacks required IAM permissions\n       lastTransitionTime: \"2024-01-15T10:30:00Z\"\n   ```\n\n   **Timeout scenario:**\n\n   If adapter doesn't write result file within timeout, Job status will be:\n   ```yaml\n   status:\n     conditions:\n     - type: Available\n       status: \"False\"\n       reason: AdapterTimeout\n       message: \"Adapter did not produce results within 5m0s\"\n       lastTransitionTime: \"2024-01-15T10:30:00Z\"\n   ```\n\n   **Container crash scenario:**\n\n   If adapter container exits with non-zero code, Job status will be:\n   ```yaml\n   status:\n     conditions:\n     - type: Available\n       status: \"False\"\n       reason: AdapterExitedWithError\n       message: \"Adapter container exited with code 1: Error\"\n       lastTransitionTime: \"2024-01-15T10:30:00Z\"\n   ```\n\n   **OOMKilled scenario:**\n\n   If adapter container is killed due to memory limits:\n   ```yaml\n   status:\n     conditions:\n     - type: Available\n       status: \"False\"\n       reason: AdapterOOMKilled\n       message: \"Adapter container was killed due to out of memory (OOMKilled)\"\n       lastTransitionTime: \"2024-01-15T10:30:00Z\"\n   ```\n\n   **Invalid result format:**\n\n   If adapter writes invalid JSON or schema:\n   ```yaml\n   status:\n     conditions:\n     - type: Available\n       status: \"False\"\n       reason: InvalidResultFormat\n       message: \"Failed to parse adapter result: status: must be either 'success' or 'failure'\"\n       lastTransitionTime: \"2024-01-15T10:30:00Z\"\n   ```\n\n5. **Shared Volume Configuration:**\n\n   Both adapter and status reporter containers must share a volume mounted at `/results`:\n\n   ```yaml\n   volumes:\n   - name: results\n     emptyDir: {}\n\n   containers:\n   - name: adapter\n     volumeMounts:\n     - name: results\n       mountPath: /results\n\n   - name: status-reporter\n     volumeMounts:\n     - name: results\n       mountPath: /results\n   ```\n\n## Configuration\n\nThe status reporter is configured exclusively through environment variables. Below is a complete reference of all supported configuration options.\n\n### Environment Variables\n\n| Environment Variable | Type | Required | Default | Description |\n|---------------------|------|----------|---------|-------------|\n| `JOB_NAME` | string | **Yes** | - | Name of the Kubernetes Job to update |\n| `JOB_NAMESPACE` | string | **Yes** | - | Namespace of the Kubernetes Job |\n| `POD_NAME` | string | **Yes** | - | Name of the current Pod (typically injected via downward API) |\n| `RESULTS_PATH` | string | No | `/results/adapter-result.json` | Absolute path to the adapter result file (must be a file, not a directory) |\n| `POLL_INTERVAL_SECONDS` | integer | No | `2` | Interval in seconds between result file checks (must be positive and less than MAX_WAIT_TIME_SECONDS) |\n| `MAX_WAIT_TIME_SECONDS` | integer | No | `300` | Maximum time in seconds to wait for adapter results before timing out (must be positive) |\n| `CONDITION_TYPE` | string | No | `Available` | Kubernetes condition type to set on the Job status |\n| `LOG_LEVEL` | string | No | `info` | Logging verbosity level |\n| `ADAPTER_CONTAINER_NAME` | string | No | `\"\"` (auto-detect) | Name of the adapter container to monitor; if empty, automatically detects the first non-reporter container in the Pod |\n\n### Configuration Example\n\nHere's a complete example showing how to configure the status reporter. \n### RBAC configuration for Job Status Reporter\n```yaml\n---\n# ServiceAccount for the validator job\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: status-reporter-sa\n  namespace: \u003cnamespace\u003e\n\n---\n# Role with necessary permissions for status reporter\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: status-reporter\n  namespace: \u003cnamespace\u003e\nrules:\n# Permission to get and update job status\n- apiGroups: [\"batch\"]\n  resources: [\"jobs\"]\n  verbs: [\"get\"]\n- apiGroups: [\"batch\"]\n  resources: [\"jobs/status\"]\n  verbs: [\"get\", \"update\", \"patch\"]\n# Permission to get pod status\n- apiGroups: [\"\"]\n  resources: [\"pods\"]\n  verbs: [\"get\", \"list\"]\n\n---\n# RoleBinding to grant permissions to the service account\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: status-reporter\n  namespace: \u003cnamespace\u003e\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: status-reporter\nsubjects:\n- kind: ServiceAccount\n  name: status-reporter-sa\n  namespace: \u003cnamespace\u003e\n```\n```bash\nsed 's/\u003cnamespace\u003e/your-namespace/g' rbac.yaml | kubectl apply -f -\n```\n\n### K8s Job configuration for Status Reporter\n```yaml\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: my-adapter-job\n  namespace: \u003cnamespace\u003e\nspec:\n  backoffLimit: 0\n  activeDeadlineSeconds: 310  # 300 adapter timeout + 10 second buffer\n  template:\n    spec:\n      serviceAccountName: status-reporter-sa   \n      volumes:\n      - name: results\n        emptyDir: {}\n\n      containers:\n      # Replace with real adapter information\n      - name: my-adapter\n        image: busybox:1.36\n        imagePullPolicy: IfNotPresent\n\n        # Adapter writes results to shared volume\n        volumeMounts:\n        - name: results\n          mountPath: /results\n\n        # Simulate adapter work and write result file\n        command:\n        - /bin/sh\n        - -c\n        - |\n          echo \"Simulating adapter validation work...\"\n          sleep 3\n          # Write adapter result in the expected JSON format\n          # Success example:\n          cat \u003e $RESULTS_PATH \u003c\u003c'EOF'\n          {\n            \"status\": \"success\",\n            \"reason\": \"GCPValidationPassed\",\n            \"message\": \"All GCP infrastructure validations completed successfully\",\n            \"details\": {\n              \"validations_run\": 5,\n              \"validations_passed\": 5,\n              \"checks\": [\n                \"VPC configuration validated\",\n                \"IAM permissions verified\",\n                \"DNS settings confirmed\",\n                \"Network policies applied\",\n                \"Resource quotas checked\"\n              ],\n              \"duration_seconds\": 3,\n              \"gcp_project\": \"example-project-123\"\n            }\n          }\n          EOF\n\n          echo \"Adapter result written to $RESULTS_PATH\"\n          cat $RESULTS_PATH\n          sleep 5\n        env:\n        - name: RESULTS_PATH\n          value: \"/results/adapter-result.json\"\n\n      - name: status-reporter\n        image: \u003cstatus-reporter-image\u003e\n        env:\n        # Required configuration\n        - name: JOB_NAME\n          value: my-adapter-job\n        - name: JOB_NAMESPACE\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.namespace\n        - name: POD_NAME\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.name\n\n        # Optional configuration (shown with non-default values)\n        - name: RESULTS_PATH\n          value: \"/results/adapter-result.json\"\n        - name: POLL_INTERVAL_SECONDS\n          value: \"5\"\n        - name: MAX_WAIT_TIME_SECONDS\n          value: \"300\"  # 5 minutes\n        - name: CONDITION_TYPE\n          value: \"Available\"\n        - name: LOG_LEVEL\n          value: \"info\"\n        - name: ADAPTER_CONTAINER_NAME\n          value: \"my-adapter\"\n\n        volumeMounts:\n        - name: results\n          mountPath: /results\n\n      restartPolicy: Never\n```\n\n```bash\nsed -e 's|\u003cnamespace\u003e|your-namespace|g' \\\n    -e 's|\u003cstatus-reporter-image\u003e|quay.io/rh-ee-dawang/status-reporter:dev-04e8d0a|g' \\\n    job.yaml | kubectl apply -f -\n```\n\n## Repository Structure\n\n```text\nstatus-reporter/\n├── cmd/reporter/         # Main entry point\n├── pkg/                  # Core packages (reporter, k8s, result parser)\n├── Dockerfile            # Container image definition\n├── Makefile              # Build, test, and image targets\n└── README.md             # This file\n```\n\n## Quick Start\n\nThe status reporter is production-ready and can be used with any adapter container.\n\n### Makefile Usage\n\n```bash\n$ make\nAvailable targets:\nbinary               Build binary\nclean                Clean build artifacts and test coverage files\nfmt                  Format code with gofmt and goimports\nhelp                 Display this help message\nimage-dev            Build and push to personal Quay registry (requires QUAY_USER)\nimage-push           Build and push container image to registry\nimage                Build container image with Docker or Podman\nlint                 Run golangci-lint\nmod-tidy             Tidy Go module dependencies\ntest-coverage-html   Generate HTML coverage report\ntest-coverage        Run unit tests with coverage report\ntest                 Run unit tests with race detection\nverify               Run all verification checks (lint + test)\n```\n\n## License\n\nSee LICENSE file for details.\n\n## Contact\n\nFor questions or issues, please open a GitHub issue in this repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenshift-hyperfleet%2Fstatus-reporter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenshift-hyperfleet%2Fstatus-reporter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenshift-hyperfleet%2Fstatus-reporter/lists"}