diff --git a/QUICKSTART.md b/QUICKSTART.md index 65344de..87e194b 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -89,6 +89,7 @@ variables, not committed to the file: | `KERNELCI_API_BASE_URI` | `kernelci.api_base_uri` | API URL | | `KERNELCI_API_TOKEN` | `kernelci.api_token` | Bearer token for the API (optional for public endpoints) | | `KERNELCI_RUNTIME_NAME` | `kernelci.runtime_name` | Lab/runtime to consume jobs for | +| `KERNELCI_PLATFORMS` | `kernelci.platforms` | Comma-separated allowlist of `node.data.platform` values. Optional; used to split one runtime label across multiple pollers (e.g. arm64 vs x86_64). Omit to accept any platform. | | `KCIDB_SUBMIT_URL` | `kernelci.kcidb_submit_url` | kcidb-restd-rs submit URL | | `KCIDB_JWT` | `kernelci.kcidb_jwt` | JWT bearer token | | `KCIDB_REST` | (alternative to the two above) | `https://@host[/path]` — kci-dev-compatible single URL carrying both endpoint and token | diff --git a/examples/aws/config-arm64.json b/examples/aws/config-arm64.json index bde386d..3e934f6 100644 --- a/examples/aws/config-arm64.json +++ b/examples/aws/config-arm64.json @@ -203,13 +203,14 @@ "kernelci": { "api_base_uri": "https://staging.kernelci.org:9000/latest", "api_token": null, - "runtime_name": "pull-labs-aws-ec2-arm64", + "runtime_name": "pull-labs-aws-ec2", + "platforms": ["aws-ec2-arm64"], "poll_interval_sec": 30, "cursor_file": "/tmp/pullab_cloud_cursor_arm64.json", "kcidb_submit_url": "https://db.kernelci.org/submit", "kcidb_origin": "pullab_cloud_aws_arm64", "kcidb_jwt": null, - "comment": "arm64 (Graviton) variant. kcidb_jwt and api_token are normally provided via the KCIDB_JWT / KERNELCI_API_TOKEN env vars (or UNIFIED_TOKEN as a shared fallback for both); leave null in the file and inject at runtime." + "comment": "arm64 (Graviton) variant. Shares runtime_name 'pull-labs-aws-ec2' with the x86 config; platforms filter narrows to arm64 jobs. kcidb_jwt and api_token are normally provided via the KCIDB_JWT / KERNELCI_API_TOKEN env vars (or UNIFIED_TOKEN as a shared fallback for both); leave null in the file and inject at runtime." }, "test_config": { "test_id": "test-all-tests", diff --git a/examples/aws/config.json b/examples/aws/config.json index e0ea898..fe9c435 100644 --- a/examples/aws/config.json +++ b/examples/aws/config.json @@ -204,12 +204,13 @@ "api_base_uri": "https://staging.kernelci.org:9000/latest", "api_token": null, "runtime_name": "pull-labs-aws-ec2", + "platforms": ["aws-ec2-x86_64"], "poll_interval_sec": 30, "cursor_file": "/tmp/pullab_cloud_cursor.json", "kcidb_submit_url": "https://db.kernelci.org/submit", "kcidb_origin": "pullab_cloud_aws", "kcidb_jwt": null, - "comment": "kcidb_jwt and api_token are normally provided via the KCIDB_JWT / KERNELCI_API_TOKEN env vars (or UNIFIED_TOKEN as a shared fallback for both); leave null in the file and inject at runtime." + "comment": "x86_64 variant. Shares runtime_name 'pull-labs-aws-ec2' with the arm64 config; platforms filter narrows to x86_64 jobs. Remove 'platforms' to accept any AWS pull-lab job. kcidb_jwt and api_token are normally provided via the KCIDB_JWT / KERNELCI_API_TOKEN env vars (or UNIFIED_TOKEN as a shared fallback for both); leave null in the file and inject at runtime." }, "test_config": { "test_id": "test-all-tests", diff --git a/src/kernel_ci_cloud_labs/pull_labs_poller.py b/src/kernel_ci_cloud_labs/pull_labs_poller.py index cd9934a..d748b5a 100644 --- a/src/kernel_ci_cloud_labs/pull_labs_poller.py +++ b/src/kernel_ci_cloud_labs/pull_labs_poller.py @@ -55,6 +55,10 @@ ENV_API_BASE_URI = "KERNELCI_API_BASE_URI" ENV_API_TOKEN = "KERNELCI_API_TOKEN" ENV_RUNTIME_NAME = "KERNELCI_RUNTIME_NAME" +# Optional comma-separated allowlist of node.data.platform values. When set, +# events whose platform isn't in the list are skipped — useful for running +# parallel pollers on the same runtime label but distinct hardware. +ENV_PLATFORMS = "KERNELCI_PLATFORMS" ENV_KCIDB_URL = "KCIDB_SUBMIT_URL" ENV_KCIDB_JWT = "KCIDB_JWT" ENV_KCIDB_ORIGIN = "KCIDB_ORIGIN" @@ -239,6 +243,7 @@ def __init__( os.getenv(ENV_RUNTIME_NAME) or kc.get("runtime_name"), "kernelci.runtime_name", ) + self.platforms: Optional[List[str]] = self._resolve_platforms(kc) # Resolution order for the KCIDB endpoint + token, matching kci-dev's # priority: explicit URL+JWT > KCIDB_REST combined env > config values. kcidb_url, kcidb_jwt = self._resolve_kcidb_endpoint(kc) @@ -320,9 +325,30 @@ def fetch_events(self, from_ts: str) -> List[Dict[str, Any]]: def _matches_runtime(self, event: Dict[str, Any]) -> bool: node = event.get("node") or {} - data = (node.get("data") or {}).get("data") or {} + data = node.get("data") or {} return data.get("runtime") == self.runtime_name + def _matches_platform(self, event: Dict[str, Any]) -> bool: + if not self.platforms: + return True + node = event.get("node") or {} + data = node.get("data") or {} + return data.get("platform") in self.platforms + + @staticmethod + def _resolve_platforms(kc: Dict[str, Any]) -> Optional[List[str]]: + raw = os.getenv(ENV_PLATFORMS) + if raw is None: + raw = kc.get("platforms") + if raw is None: + return None + if isinstance(raw, str): + items = [p.strip() for p in raw.split(",")] + else: + items = [str(p).strip() for p in raw] + items = [p for p in items if p] + return items or None + def _job_definition_url(self, event: Dict[str, Any]) -> Optional[str]: node = event.get("node") or {} artifacts = node.get("artifacts") or {} @@ -369,6 +395,10 @@ def process_event(self, event: Dict[str, Any]) -> bool: logger.debug("Skipping event %s: runtime mismatch", node_id) return True + if not self._matches_platform(event): + logger.debug("Skipping event %s: platform mismatch", node_id) + return True + jobdef_url = self._job_definition_url(event) if not jobdef_url: logger.debug("Skipping event %s: no job_definition artifact", node_id)