diff --git a/README.md b/README.md index c5533ed..360b8b0 100755 --- a/README.md +++ b/README.md @@ -122,9 +122,15 @@ curl -X POST http://localhost:8000/api/hyperfleet/v1/clusters \ # Search clusters curl -G http://localhost:8000/api/hyperfleet/v1/clusters \ - --data-urlencode "search=labels.env='production'" | jq + --data-urlencode "search=labels.environment='production'" | jq + +# Search ready clusters in a specific region +curl -G http://localhost:8000/api/hyperfleet/v1/clusters \ + --data-urlencode "search=status.conditions.Ready='True' and labels.region='us-east'" | jq ``` +See [docs/search.md](docs/search.md) for search and filtering documentation. + ## Development ### Common Commands @@ -161,6 +167,7 @@ This project uses [pre-commit](https://pre-commit.io/) for code quality checks. ### Additional Resources - **[PREREQUISITES.md](PREREQUISITES.md)** - Prerequisite installation +- **[Search and Filtering](docs/search.md)** - Guide to TSL query syntax, operators, and examples - **[docs/continuous-delivery-migration.md](docs/continuous-delivery-migration.md)** - CD migration guide - **[docs/dao.md](docs/dao.md)** - Data access patterns - **[docs/testcontainers.md](docs/testcontainers.md)** - Testcontainers usage diff --git a/docs/api-resources.md b/docs/api-resources.md index c0b1666..fa83ebf 100644 --- a/docs/api-resources.md +++ b/docs/api-resources.md @@ -408,40 +408,14 @@ GET /api/hyperfleet/v1/clusters?page=1&pageSize=10 ### Search -Search using TSL (Tree Search Language) query syntax: +All list endpoints support filtering using TSL (Tree Search Language) query syntax. Example: ```bash -# Simple equality -curl -G http://localhost:8000/api/hyperfleet/v1/clusters \ - --data-urlencode "search=name='my-cluster'" - -# AND query with condition-based status curl -G http://localhost:8000/api/hyperfleet/v1/clusters \ --data-urlencode "search=status.conditions.Ready='True' and labels.environment='production'" - -# OR query -curl -G http://localhost:8000/api/hyperfleet/v1/clusters \ - --data-urlencode "search=labels.environment='dev' or labels.environment='staging'" - -# Query for available resources -curl -G http://localhost:8000/api/hyperfleet/v1/clusters \ - --data-urlencode "search=status.conditions.Available='True'" ``` -**Supported fields:** - -- `name` - Resource name -- `status.conditions.` - Condition status (True, False). Examples: - - `status.conditions.Ready='True'` - Resources that are ready - - `status.conditions.Available='True'` - Resources that are available -- `labels.` - Label values - -**Supported operators:** - -- `=` - Equality -- `in` - In list -- `and` - Logical AND -- `or` - Logical OR +See **[search.md](search.md)** for complete documentation. ## Field Descriptions diff --git a/docs/search.md b/docs/search.md new file mode 100644 index 0000000..61ecec7 --- /dev/null +++ b/docs/search.md @@ -0,0 +1,165 @@ +# API Search and Filtering + +This document describes how to search and filter resources in the HyperFleet API using TSL (Tree Search Language) queries. + +## Overview + +The HyperFleet API supports search and filtering capabilities through the `search` query parameter. All list endpoints (`GET /clusters`, `GET /nodepools`, etc.) accept TSL (Tree Search Language) queries that allow you to filter results using field comparisons, logical operators, and complex nested conditions. + +## TSL Language Reference + +The HyperFleet API uses the [Tree Search Language (TSL)](https://github.com/yaacov/tree-search-language) library for parsing search queries. + +### Supported Operators + +| Operator | Description | Example | +|----------|-------------|---------| +| `=` | Equal | `name='test'` | +| `!=` | Not equal | `name!='old'` | +| `<` | Less than | `generation<10` | +| `<=` | Less than or equal | `generation<=5` | +| `>` | Greater than | `generation>1` | +| `>=` | Greater than or equal | `generation>=1` | +| `in` | In list | `name in ('c1','c2')` | +| `and` | Logical AND | `a='1' and b='2'` | +| `or` | Logical OR | `a='1' or a='2'` | +| `not` | Logical NOT | `not name='test'` | + +### Query Value Syntax + +- **String values**: Must be enclosed in single quotes: `name='my-cluster'` +- **Numeric values**: No quotes required: `generation>5` +- **Lists**: Comma-separated values in parentheses: `id in ('2abc123', '2def456')` + +## Searchable Fields + +### Clusters + +| Field | Type | Description | Example | +|-------|------|-------------|---------| +| `id` | string | Cluster ID | `id='2abc123'` | +| `name` | string | Cluster name | `name='my-cluster'` | +| `generation` | integer | Spec version counter | `generation>1` | +| `created_by` | string | Creator email | `created_by='user@example.com'` | +| `updated_by` | string | Last updater email | `updated_by='user@example.com'` | +| `labels.` | string | Label value | `labels.environment='production'` | +| `status.conditions.` | string | Condition status | `status.conditions.Ready='True'` | + +```bash +# Find cluster by name +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=name='my-cluster'" + +# Find clusters by multiple names +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=name in ('cluster1', 'cluster2', 'cluster3')" +``` + +### NodePools + +NodePools support the same searchable fields as Clusters, plus: + +| Field | Type | Description | Example | +|-------|------|-------------|---------| +| `owner_id` | string | Parent cluster ID | `owner_id='2abc123'` | + +```bash +# Find nodepools by parent cluster ID +curl -G "http://localhost:8000/api/hyperfleet/v1/nodepools" \ + --data-urlencode "search=owner_id='2abc123'" + +# Find ready nodepools +curl -G "http://localhost:8000/api/hyperfleet/v1/nodepools" \ + --data-urlencode "search=status.conditions.Ready='True'" + +# Find nodepools by label +curl -G "http://localhost:8000/api/hyperfleet/v1/nodepools" \ + --data-urlencode "search=labels.role='worker'" +``` + +## Labels Queries + +Use `labels.` syntax to filter by label values: + +```bash +# Find production clusters +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=labels.environment='production'" + +# Find clusters in a specific region +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=labels.region='us-east'" +``` + +Label keys must contain only lowercase letters (a-z), digits (0-9), and underscores (_). + +## Status Condition Queries + +Query resources by status conditions: `status.conditions.=''` + +Condition types must be PascalCase (`Ready`, `Available`) and status must be `True` or `False` for resource conditions. + +```bash +# Find available clusters +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=status.conditions.Available='True'" + +# Find clusters that are not ready +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=status.conditions.Ready='False'" +``` + +## Complex Queries + +Combine multiple conditions using `and`, `or`, `not`, and parentheses `()`: + +```bash +# Find ready production clusters +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=status.conditions.Ready='True' and labels.environment='production'" + +# Find clusters in dev or staging +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=labels.environment in ('dev', 'staging')" + +# Find ready clusters in production or staging +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=status.conditions.Ready='True' and (labels.environment='production' or labels.environment='staging')" + +# Find clusters that are not in production +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=not labels.environment='production'" +``` + +Operator precedence: `()` > comparisons > `not` > `and` > `or` + +## Other Common Use Cases + +```bash +# Find non-production clusters +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=labels.environment in ('dev', 'staging', 'test')" + +# Find clusters created by specific user +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=created_by='user@example.com'" + +# Find clusters by multiple IDs +curl -G "http://localhost:8000/api/hyperfleet/v1/clusters" \ + --data-urlencode "search=id in ('2abc123', '2def456', '2ghi789')" +``` + +## Error Handling + +Invalid queries return `400 Bad Request` with error details: + +```json +{ + "type": "https://api.hyperfleet.io/errors/bad-request", + "title": "Bad Request", + "status": 400, + "detail": "Failed to parse search query: invalid-query", + "code": "HYPERFLEET-VAL-005", + "timestamp": "2025-01-15T10:30:00Z" +} +```