Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions cluster-update/product-lifecycle/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
name: product-lifecycle
description: Query Red Hat Product Life Cycle data for support phases, end-of-life dates, and OpenShift version compatibility. Use when evaluating whether installed operators or layered products are supported on a given OCP version, approaching end of life, or need upgrading before a cluster upgrade. Also use when the user asks about product support status, EOL dates, or lifecycle phases for any Red Hat product.
---

# Red Hat Product Life Cycle

Query the Red Hat Product Life Cycle API to check support status, EOL dates, and OpenShift compatibility for Red Hat products and layered operators.

## API Overview

- **Base URL**: `https://access.redhat.com/product-life-cycles/api/v1/products`
- **Authentication**: None required — the API is public.
- **Query parameter**: `?name=<substring>` — case-insensitive substring match on product name.
- **Response**: `{ "data": [ { product }, ... ] }` — array of matching products.

## Quick Start

```bash
# Search for a product by name (substring match)
curl -s "https://access.redhat.com/product-life-cycles/api/v1/products?name=logging+for+Red+Hat+OpenShift" | jq .

# List all products with "OpenShift" in the name
curl -s "https://access.redhat.com/product-life-cycles/api/v1/products?name=OpenShift" | jq -r '.data[].name'
```

## Response Structure

Each product in `data[]` has:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it overlaps with api-details.md? Is the goal here just to cover some of the highlights of the response format, without swamping with context? Maybe we should suggest using a sub-agent that has read the whole api-details.md file, to try to preserve that context capacity, at the cost of restricting use to agents that can launch sub-agents? Or offload PLC queries to an MCP tool, instead of using a Skill? Or...?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, you're right. There was genuine duplication here and it was already causing drift (the type field table in SKILL.md was stale). I've removed the duplicated Key fields and Phase date formats sections from SKILL.md, keeping just the JSON example and a pointer to api-details.md.

The intent is progressive disclosure. I want to give the agent just enough to work with for typical queries without loading the full schema into context. If the agent needs the full field details, type enumerations, or phase name breakdown, it can read api-details.md on demand.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved by 23c5759 -> 804b96b dropping the "Key fields" and "Phase date formats" sections from SKILL.md; thanks 👍


```json
{
"name": "logging for Red Hat OpenShift",
"former_names": ["Red Hat OpenShift Logging"],
"all_phases": [{"name": "General availability", ...}, ...],
"versions": [
{
"name": "6.5",
"type": "Full Support",
"openshift_compatibility": "4.19, 4.20, 4.21",
"phases": [
{
"name": "General availability",
"end_date": "2026-04-01T00:00:00.000Z",
"date_format": "date"
},
{
"name": "Full support",
"end_date": "Release of Logging 6.6 + 1 month",
"date_format": "string"
},
{
"name": "Maintenance support",
"end_date": "Release of Logging 6.7",
"date_format": "string"
}
]
}
]
}
```

For full field descriptions, type enumerations, and phase name details, see `references/api-details.md`.

## Common Queries

### Check support status for a specific product version

```bash
curl -s "https://access.redhat.com/product-life-cycles/api/v1/products?name=logging+for+Red+Hat+OpenShift" \
| jq -r '.data[] | "\(.name)", (.versions[] | " \(.name) - \(.type) (OCP: \(.openshift_compatibility // "N/A"))")'
```

### Check if a product version is compatible with a target OCP version

```bash
TARGET_OCP="4.21"
PRODUCT="logging+for+Red+Hat+OpenShift"

curl -s "https://access.redhat.com/product-life-cycles/api/v1/products?name=$PRODUCT" \
| jq -r --arg target "$TARGET_OCP" '
.data[] | .name as $prod |
.versions[] |
.name as $ver | .type as $type |
(.openshift_compatibility // "" | split(", ")) as $compat |
(if ($compat | index($target)) then "COMPATIBLE" else "NOT COMPATIBLE" end) as $status |
"\($prod) \($ver) (\($type)) - \($status) with OCP \($target)"'
```

### Get EOL dates for OCP itself

```bash
curl -s "https://access.redhat.com/product-life-cycles/api/v1/products?name=OpenShift+Container+Platform" \
| jq -r '.data[0].versions[] |
"OCP \(.name) - \(.type) (maintenance ends: \(
[.phases[] | select(.name == "Maintenance support") | .end_date] | first // "N/A"
))"'
```

### Cross-reference OLM operators with Product Life Cycle data

Products that are OLM operators have a `package` field that maps directly to the
OLM Subscription's `spec.name`. This is an **exact match key** — more reliable than name
matching. The `is_operator` field confirms the product is OLM-managed.

When the upgrade advisor readiness JSON includes `olm_operator_lifecycle` data:

1. Extract the `package` name from each operator in readiness data
2. Search the Product Life Cycle API using that package name
3. Match by comparing `product.package` == operator's `package`
4. Check if the installed version's `openshift_compatibility` includes the target OCP version
5. Check the `type` field for support status

```bash
# Look up Product Life Cycle data for an OLM operator by its package name
OLM_PACKAGE="cluster-logging"
TARGET_OCP="4.21"

curl -s "https://access.redhat.com/product-life-cycles/api/v1/products?name=logging" \
| jq -r --arg pkg "$OLM_PACKAGE" --arg target "$TARGET_OCP" '
[.data[] | select(.package == $pkg)] |
if length == 0 then "No Product Life Cycle entry with package=\($pkg)"
else .[0] |
"\(.name) (package: \(.package))",
(.versions[] |
.name as $ver | .type as $type |
(.openshift_compatibility // "" | split(", ")) as $compat |
(if ($compat | index($target)) then "YES" else "NO" end) as $ok |
" \($ver) - \($type) - OCP \($target) compatible: \($ok)")
end'
```

If the `?name=` search doesn't return the operator, try searching by `csv_display_name`
from the readiness data as a fallback.

**Not all operators have Product Life Cycle entries.** If a search returns no results, that's expected —
it means the product isn't tracked in the Product Life Cycle API. Report this as "lifecycle data unavailable"
rather than an error.

### Batch lookup for multiple OLM operators

When cross-referencing several operators, avoid N+1 API calls. Fetch `?name=OpenShift`
once (~14 products covering most Red Hat layered operators), then make individual calls
only for operators not found in that initial batch.

```bash
TARGET_OCP="4.21"

# Single call covers most Red Hat operator products
curl -s "https://access.redhat.com/product-life-cycles/api/v1/products?name=OpenShift" \
| jq -r --arg target "$TARGET_OCP" '
.data[] | select(.is_operator) |
(.package // "") as $pkg | .name as $prod |
.versions[] |
.name as $ver | .type as $type |
(.openshift_compatibility // "" | split(", ")) as $compat |
(if ($compat | index($target)) then "YES" else "NO" end) as $ok |
"\($pkg): \($prod) \($ver) (\($type)) - OCP \($target): \($ok)"'
```

## Important

- **Always use `?name=`** to filter — never fetch the unfiltered `/products` endpoint.
- `openshift_compatibility` is only present on **layered product** versions, not on OCP itself.
- When cross-referencing with OLM data, a missing Product Life Cycle entry is normal — report "lifecycle data unavailable" and move on.
82 changes: 82 additions & 0 deletions cluster-update/product-lifecycle/references/api-details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Product Life Cycle API Reference

## Endpoint

```
GET https://access.redhat.com/product-life-cycles/api/v1/products?name=<substring>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: there's now a v2 lifecycle API at https://access.redhat.com/product-life-cycles/api/v2/products . It has a slightly different schema, e.g.:

$ diff -u3 <(curl -s 'https://access.redhat.com/product-life-cycles/api/v1/products?name=OpenShift+Container+Platform' | jq -S .) <(curl -s 'https://access.redhat.com/product-life-cycles/api/v2/products?name=OpenShift+Container+Platform' | jq -S .) | head -n30
--- /dev/fd/63	2026-04-21 13:36:54.495565201 -0700
+++ /dev/fd/62	2026-04-21 13:36:54.495565201 -0700
@@ -61,27 +61,23 @@
       "is_retired": false,
       "link": "https://access.redhat.com/support/policy/updates/openshift/",
       "name": "Red Hat OpenShift Container Platform",
+      "opl_uuid": null,
       "package": null,
       "policies": "https://access.redhat.com/site/support/policy/updates/openshift/policies/",
       "release_cadence": "4 months ",
       "show_final_minor_release": false,
-      "show_last_minor_release": false,
       "show_openshift_compatibility": false,
       "uuid": "9bbc4758-50e0-4b73-89dc-2bae80f1d394",
       "versions": [
         {
           "additional_text": "",
           "extra_dependences": [],
-          "extra_header_value": null,
           "final_minor_release": null,
-          "last_minor_release": null,
           "name": "4.21",
           "openshift_compatibility": null,
           "phases": [
             {
               "additional_text": "",
-              "date": "2026-02-03T00:00:00.000Z",
-              "date_format": "date",
               "end_date": "2026-02-03T00:00:00.000Z",
               "end_date_format": "date",

We probably want the skill to use the v2 API, but I'm agnostic about whether we port from v1 to v2 in this pull or, after merging this as it stands, in follow-up pulls.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, we will introduce v2 usage in #13

```

No authentication required. The `name` parameter is a case-insensitive substring match.

## Product Object

| Field | Type | Description |
|---|---|---|
| `name` | string | Current product name |
| `former_names` | string[] | Previous product names (useful for search fallback) |
| `is_operator` | bool | Whether this product is an OLM-managed operator |
| `is_layered_product` | bool | Whether this product is layered on OpenShift |
| `is_retired` | bool | Whether the entire product has been retired |
| `package` | string\|null | **OLM package name** — maps to Subscription `spec.name` |
| `versions` | object[] | Per-version lifecycle data |

### The `package` field

The `package` field is the OLM package name and provides an **exact match key** to correlate
Product Life Cycle products with OLM Subscriptions. This is more reliable than name matching.

Mapping: `product.package` == `subscription.spec.name`

## Version Object

| Field | Type | Description |
|---|---|---|
| `name` | string | Version number (e.g., `"6.5"`, `"4.21"`) |
| `type` | string | **Current support status** — see table below |
| `openshift_compatibility` | string\|null | Comma-separated OCP versions (e.g., `"4.19, 4.20, 4.21"`) — only on layered products |
| `phases` | object[] | Lifecycle phase details with dates |

### Support status (`type`)

| Value | Meaning |
|---|---|
| `"Full Support"` | Active development, bug fixes, security patches |
| `"Maintenance Support"` | Critical/security fixes only, no new features |
| `"End of Maintenance"` | Maintenance support has ended; no EUS/ELS applies to this version |
| `"Extended Support"` | Past maintenance, currently in a paid Extended Life Cycle Support (ELS) phase |
| `"End of life"` | No fixes, no support — must upgrade |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ curl -s https://access.redhat.com/product-life-cycles/api/v1/products | jq -r '.data[].versions[].type' | sort | uniq -c | sort -n
     12 
     39 End of Maintenance
    119 Extended Support
    156 Maintenance Support
    257 Full Support
    875 End of life

I'm not clear on what End of Maintenance means. Extended Support is similar to Maintenance Support, but might come with additional restrictions like the need to purchase add-ons. Would be nice if there were OpenAPI schemas for this endpoint, and maybe there are, and I'm just not aware of them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I've updated the table to include all six type values the API actually returns: Full Support, Maintenance Support, End of Maintenance, Extended Support, End of life, and empty string. Verified against the live API.

Agreed on the OpenAPI schemas, I'm not aware of any either.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved by 23c5759 -> 804b96b adding coverage for End of Maintenance, Extended Support, and the empty string; thanks 👍

| `""` (empty) | Status not yet determined (e.g., version has incomplete lifecycle data) |

## Phase Object

| Field | Type | Description |
|---|---|---|
| `name` | string | Phase name (e.g., `"General availability"`, `"Full support"`, `"Maintenance support"`) |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ curl -s https://access.redhat.com/product-life-cycles/api/v1/products | jq -r '.data[].versions[].phases[].name' | sort | uniq -c | sort -n
      3 Migration support
      5 Retired
     18 Extended life cycle support (ELS) Term 3 add-on
     18 Third-party certification period
     26 Maintenance support 2
     29 Extended life cycle support (ELS) Term 2 add-on
     36 Maintenance Support 1
     38 Extended life cycle support (ELS) 2
     75 Extended life cycle support (ELS) add-on
     85 Extended life cycle support (ELS) 1
    125 Extended life phase
    298 Extended update support Term 3
    331 End of Life
    453 Extended update support Term 2
    583 Extended update support
   1161 Maintenance support
   1289 Full support
   1458 General availability

Maybe the API needs a link from each phase to docs about what that phase means for that product? Because that seems like a lot of phases that aren't all that clear to me as someone not terribly familiar with a bunch of these products.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, I will update that file. Thanks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved by 23c5759 -> 804b96b adding coverage for Extended life phase, Extended update support Term 2, Retired, End of Life, Migration support, Third-party certification period, etc.; thanks 👍

| `start_date` | string | Phase start — ISO 8601 date or descriptive string |
| `end_date` | string | Phase end — ISO 8601 date or descriptive string |
| `date_format` | string | `"date"` (ISO 8601) or `"string"` (relative/TBD) |

Phase names vary by product. Common categories:

| Category | Phase names | Meaning |
|---|---|---|
| Release | `General availability` | When the version was first released |
| Active support | `Full support` | Active development, bug fixes, security patches |
| Reduced support | `Maintenance support`, `Maintenance Support 1`, `Maintenance support 2` | Critical/security fixes only |
| Extended support | `Extended update support`, `Extended update support Term 2`, `Extended update support Term 3` | EUS — available for select versions, may require add-on purchase |
| Extended lifecycle | `Extended life phase`, `Extended life cycle support (ELS) 1`/`2`, `Extended life cycle support (ELS) add-on`/`Term 2 add-on`/`Term 3 add-on` | Paid extended support beyond normal EOL |
| End | `End of Life`, `Retired` | No further updates or support |
| Other | `Migration support`, `Third-party certification period` | Product-specific transitional phases |

Phase names are not standardized across products. Use the `start_date` and `end_date` fields
to determine whether a phase is current, rather than relying on the phase name alone.

For detailed lifecycle policy definitions, see the [Red Hat product lifecycle policies](https://access.redhat.com/support/policy/updates/openshift#dates).

## Search Tips

1. **Be specific with `?name=`** — `"logging+for+Red+Hat+OpenShift"` is better than `"logging"`
2. **Check `former_names`** — products may appear under a previous name in the `former_names` field
3. **Use `is_operator: true`** to filter for OLM operators in results
4. **Use `package` for OLM correlation** — more reliable than name matching
5. **Never omit `?name=`** — the unfiltered response is very large
Loading