diff --git a/docs/api-reference/catalogd-api-reference.md b/docs/api-reference/catalogd-api-reference.md index fa52fbc00..90ec13904 100644 --- a/docs/api-reference/catalogd-api-reference.md +++ b/docs/api-reference/catalogd-api-reference.md @@ -116,10 +116,26 @@ _Appears in:_ | --- | --- | --- | --- | | `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#condition-v1-meta) array_ | conditions is a representation of the current state for this ClusterCatalog.
The status is represented by a set of "conditions".

Each condition is generally structured in the following format:
- Type: a string representation of the condition type. More or less the condition "name".
- Status: a string representation of the state of the condition. Can be one of ["True", "False", "Unknown"].
- Reason: a string representation of the reason for the current state of the condition. Typically useful for building automation around particular Type+Reason combinations.
- Message: a human-readable message that further elaborates on the state of the condition.

The current set of condition types are:
- "Serving", which represents whether or not the contents of the catalog are being served via the HTTP(S) web server.
- "Progressing", which represents whether or not the ClusterCatalog is progressing towards a new state.

The current set of reasons are:
- "Succeeded", this reason is set on the "Progressing" condition when progressing to a new state is successful.
- "Blocked", this reason is set on the "Progressing" condition when the ClusterCatalog controller has encountered an error that requires manual intervention for recovery.
- "Retrying", this reason is set on the "Progressing" condition when the ClusterCatalog controller has encountered an error that might be resolvable on subsequent reconciliation attempts.
- "Available", this reason is set on the "Serving" condition when the contents of the ClusterCatalog are being served via an endpoint on the HTTP(S) web server.
- "Unavailable", this reason is set on the "Serving" condition when there is not an endpoint on the HTTP(S) web server that is serving the contents of the ClusterCatalog. | | | | `resolvedSource` _[ResolvedCatalogSource](#resolvedcatalogsource)_ | resolvedSource contains information about the resolved source based on the source type.

Below is an example of a resolved source for an image source:
resolvedSource:

image:
lastSuccessfulPollAttempt: "2024-09-10T12:22:13Z"
ref: quay.io/operatorhubio/catalog@sha256:c7392b4be033da629f9d665fec30f6901de51ce3adebeff0af579f311ee5cf1b
type: Image | | | -| `contentURL` _string_ | contentURL is a cluster-internal URL from which on-cluster components
can read the content of a catalog | | | +| `urls` _[ClusterCatalogURLs](#clustercatalogurls)_ | urls contains the URLs that can be used to access the catalog. | | | | `lastUnpacked` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#time-v1-meta)_ | lastUnpacked represents the time when the
ClusterCatalog object was last unpacked successfully. | | | +#### ClusterCatalogURLs + + + +ClusterCatalogURLs contains the URLs that can be used to access the catalog. + + + +_Appears in:_ +- [ClusterCatalogStatus](#clustercatalogstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `base` _string_ | base is a required cluster-internal URL which provides API access for this ClusterCatalog.
A suffix API access path can be added to retrieve catalog data for the ClusterCatalog.
Currently, a 'v1' API access provides complete FBC retrival via the path "/api/v1/all", with the general form `\{base\}/api/v1/all`. | | Required: \{\}
| + + #### ImageSource diff --git a/docs/api-reference/catalogd-webserver.md b/docs/api-reference/catalogd-webserver.md index a95772ead..3aed2f6bd 100644 --- a/docs/api-reference/catalogd-webserver.md +++ b/docs/api-reference/catalogd-webserver.md @@ -3,18 +3,21 @@ [Catalogd](https://github.com/operator-framework/catalogd), the OLM v1 component for making catalog contents available on cluster, includes a web server that serves catalog contents to clients via an HTTP(S) endpoint. -The endpoint to retrieve this information is provided in the `.status.contentURL` of a `ClusterCatalog` resource. -As an example: +The endpoint to retrieve this information can be composed from the `.status.urls.base` of a `ClusterCatalog` resource with the selected access API path. +As an example, to access the full FBC via the v1 API endpoint (indicated by path `api/v1/all`) where `.status.urls.base` is ```yaml - contentURL: https://catalogd-service.olmv1-system.svc/catalogs/operatorhubio/all.json + urls: + base: https://catalogd-service.olmv1-system.svc/catalogs/operatorhubio ``` +the URL to access the service would be `https://catalogd-service.olmv1-system.svc/catalogs/operatorhubio/api/v1/all` + !!! note - The value of the `.status.contentURL` field in a `ClusterCatalog` resource is an arbitrary string value and can change at any time. - While there are no guarantees on the exact value of this field, it will always be a URL that resolves successfully for clients using - it to make a request from within the cluster. + The values of the `.status.urls` field in a `ClusterCatalog` resource are arbitrary string values and can change at any time. + While there are no guarantees on the exact value of this field, it will always contain catalog-specific API endpoints for use + by clients to make a request from within the cluster. ## Interacting With the Server diff --git a/docs/howto/catalog-queries.md b/docs/howto/catalog-queries.md index 4e6f260d7..7eadb8501 100644 --- a/docs/howto/catalog-queries.md +++ b/docs/howto/catalog-queries.md @@ -7,7 +7,7 @@ The following examples will show this default behavior, but for simplicity's sak You can use the `curl` command with `jq` to query catalogs that are installed on your cluster. ``` terminal title="Query syntax" -curl -k https://localhost:8443/catalogs/operatorhubio/all.json | +curl -k https://localhost:8443/catalogs/operatorhubio/api/v1/all | ``` ## Package queries diff --git a/docs/tutorials/add-catalog.md b/docs/tutorials/add-catalog.md index ad3ae06bb..2b75c666d 100644 --- a/docs/tutorials/add-catalog.md +++ b/docs/tutorials/add-catalog.md @@ -126,7 +126,8 @@ This catalog is distributed as an image [quay.io/operatorhubio/catalog](https:// Reason: Available Status: True Type: Serving - Content URL: https://catalogd-server.olmv1-system.svc/catalogs/operatorhubio/all.json + URLs: + Base: https://catalogd-server.olmv1-system.svc/catalogs/operatorhubio Last Unpacked: 2024-03-12T19:35:34Z Resolved Source: Image: diff --git a/docs/tutorials/explore-available-content.md b/docs/tutorials/explore-available-content.md index 67ea2127a..76bae2b6f 100644 --- a/docs/tutorials/explore-available-content.md +++ b/docs/tutorials/explore-available-content.md @@ -24,9 +24,9 @@ The following examples will show this default behavior, but for simplicity's sak kubectl -n olmv1-system port-forward svc/catalogd-service 8443:443 ``` -2. Return a list of all the extensions in a catalog: +2. Return a list of all the extensions in a catalog via the v1 API endpoint: ``` terminal - curl -k https://localhost:8443/catalogs/operatorhubio/all.json | jq -s '.[] | select(.schema == "olm.package") | .name' + curl -k https://localhost:8443/catalogs/operatorhubio/api/v1/all | jq -s '.[] | select(.schema == "olm.package") | .name' ``` ??? success @@ -96,7 +96,7 @@ The following examples will show this default behavior, but for simplicity's sak * Return list of packages that support `AllNamespaces` install mode and do not use webhooks: ``` terminal - curl -k https://localhost:8443/catalogs/operatorhubio/all.json | jq -c 'select(.schema == "olm.bundle") | {"package":.package, "version":.properties[] | select(.type == "olm.bundle.object").value.data | @base64d | fromjson | select(.kind == "ClusterServiceVersion" and (.spec.installModes[] | select(.type == "AllNamespaces" and .supported == true) != null) and .spec.webhookdefinitions == null).spec.version}' + curl -k https://localhost:8443/catalogs/operatorhubio/api/v1/all | jq -c 'select(.schema == "olm.bundle") | {"package":.package, "version":.properties[] | select(.type == "olm.bundle.object").value.data | @base64d | fromjson | select(.kind == "ClusterServiceVersion" and (.spec.installModes[] | select(.type == "AllNamespaces" and .supported == true) != null) and .spec.webhookdefinitions == null).spec.version}' ``` ??? success @@ -127,7 +127,7 @@ The following examples will show this default behavior, but for simplicity's sak 3. Inspect the contents of an extension's metadata: ``` terminal - curl -k https://localhost:8443/catalogs/operatorhubio/all.json | jq -s '.[] | select( .schema == "olm.package") | select( .name == "")' + curl -k https://localhost:8443/catalogs/operatorhubio/api/v1/all | jq -s '.[] | select( .schema == "olm.package") | select( .name == "")' ``` `package_name` diff --git a/go.mod b/go.mod index ebd0d93b8..300498b3c 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/onsi/gomega v1.34.2 github.com/opencontainers/go-digest v1.0.0 github.com/operator-framework/api v0.27.0 - github.com/operator-framework/catalogd v0.33.0 + github.com/operator-framework/catalogd v0.34.0 github.com/operator-framework/helm-operator-plugins v0.5.0 github.com/operator-framework/operator-registry v1.47.0 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index ae3144963..75efd1bdc 100644 --- a/go.sum +++ b/go.sum @@ -535,8 +535,8 @@ github.com/openshift/crd-schema-checker v0.0.0-20240404194209-35a9033b1d11 h1:eT github.com/openshift/crd-schema-checker v0.0.0-20240404194209-35a9033b1d11/go.mod h1:EmVJt97N+pfWFsli/ipXTBZqSG5F5KGQhm3c3IsGq1o= github.com/operator-framework/api v0.27.0 h1:OrVaGKZJvbZo58HTv2guz7aURkhVKYhFqZ/6VpifiXI= github.com/operator-framework/api v0.27.0/go.mod h1:lg2Xx+S8NQWGYlEOvFwQvH46E5EK5IrAIL7HWfAhciM= -github.com/operator-framework/catalogd v0.33.0 h1:hnLIFykO1FkjOAUFRPuYRIHQTE0oBF9jkGmWjKhxniQ= -github.com/operator-framework/catalogd v0.33.0/go.mod h1:anZurjcFMBvbkuyqlJ98v9z+yjniPKqmhlyitk9DuBQ= +github.com/operator-framework/catalogd v0.34.0 h1:zzCUTVrRJ4oCnjvAdairEWbUejLUnYRVsvAyhfREpyU= +github.com/operator-framework/catalogd v0.34.0/go.mod h1:anZurjcFMBvbkuyqlJ98v9z+yjniPKqmhlyitk9DuBQ= github.com/operator-framework/helm-operator-plugins v0.5.0 h1:qph2OoECcI9mpuUBtOsWOMgvpx52mPTTSvzVxICsT04= github.com/operator-framework/helm-operator-plugins v0.5.0/go.mod h1:yVncrZ/FJNqedMil+055fk6sw8aMKRrget/AqGM0ig0= github.com/operator-framework/operator-lib v0.15.0 h1:0QeRM4PMtThqINpcFGCEBnIV3Z8u7/8fYLEx6mUtdcM= diff --git a/hack/tools/catalogs/download-catalog b/hack/tools/catalogs/download-catalog index 43877690e..437cb8a75 100755 --- a/hack/tools/catalogs/download-catalog +++ b/hack/tools/catalogs/download-catalog @@ -53,12 +53,14 @@ if [ "$UNPACKED_CONDITION" != "True" ]; then exit 1 fi -# Get the contentURL -CONTENT_URL=$(echo "$CLUSTER_CATALOG" | jq -r '.status.contentURL') -if [ -z "$CONTENT_URL" ]; then - echo "Content URL not found for ClusterCatalog $CATALOG_NAME." +# Construct the API URL from the ClusterCatalog status +CATALOG_API_URL=$(echo "$CLUSTER_CATALOG" | jq -r '.status.urls.base') +if [ -z "$CATALOG_API_URL" ]; then + echo "ClusterCatalog $CATALOG_NAME does not express API endpoint in '.status.urls.base'." exit 1 fi +# Assemble the v1 API URL from the base endpoint +CATALOG_CONTENT_URL="${CATALOG_API_URL}/api/v1/all" # Start port forwarding echo "Starting kubectl port-forward to $CATALOGD_SERVICE_NAME on port $CATALOGD_LOCAL_SERVICE_PORT..." @@ -77,9 +79,9 @@ while ! curl -s "http://localhost:${CATALOGD_LOCAL_SERVICE_PORT}" >/dev/null; do sleep 1 done -# Modify the contentURL to hit localhost: -LOCAL_CONTENT_URL=${CONTENT_URL//https:\/\/$CATALOGD_SERVICE_NAME.$CATALOGD_CATALOGD_SERVICE_NAMESPACE.svc/https:\/\/localhost:$CATALOGD_LOCAL_SERVICE_PORT} -echo "Found content URL: $CONTENT_URL" +# Modify the catalogd service endpoint URL to hit localhost: +LOCAL_CONTENT_URL=${CATALOG_CONTENT_URL//https:\/\/$CATALOGD_SERVICE_NAME.$CATALOGD_CATALOGD_SERVICE_NAMESPACE.svc/https:\/\/localhost:$CATALOGD_LOCAL_SERVICE_PORT} +echo "Calculated catalogd API pathcontent URL: $CATALOG_CONTENT_URL" echo "Using local port: $CATALOGD_LOCAL_SERVICE_PORT" echo "Using local content URL: $LOCAL_CONTENT_URL" diff --git a/internal/catalogmetadata/client/client.go b/internal/catalogmetadata/client/client.go index 43b972095..fee3b1cc2 100644 --- a/internal/catalogmetadata/client/client.go +++ b/internal/catalogmetadata/client/client.go @@ -7,6 +7,7 @@ import ( "io" "io/fs" "net/http" + "net/url" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -15,6 +16,10 @@ import ( "github.com/operator-framework/operator-registry/alpha/declcfg" ) +const ( + clusterCatalogV1ApiURL = "api/v1/all" +) + type Cache interface { // Get returns cache for a specified catalog name and version (resolvedRef). // @@ -113,7 +118,16 @@ func (c *Client) PopulateCache(ctx context.Context, catalog *catalogd.ClusterCat } func (c *Client) doRequest(ctx context.Context, catalog *catalogd.ClusterCatalog) (*http.Response, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, catalog.Status.ContentURL, nil) + if catalog.Status.URLs == nil { + return nil, fmt.Errorf("error: catalog %q has a nil status.urls value", catalog.Name) + } + + catalogdURL, err := url.JoinPath(catalog.Status.URLs.Base, clusterCatalogV1ApiURL) + if err != nil { + return nil, fmt.Errorf("error forming catalogd API endpoint: %v", err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, catalogdURL, nil) if err != nil { return nil, fmt.Errorf("error forming request: %v", err) } diff --git a/internal/catalogmetadata/client/client_test.go b/internal/catalogmetadata/client/client_test.go index 92645bdbf..33f43c1cf 100644 --- a/internal/catalogmetadata/client/client_test.go +++ b/internal/catalogmetadata/client/client_test.go @@ -28,7 +28,9 @@ func defaultCatalog() *catalogd.ClusterCatalog { ResolvedSource: &catalogd.ResolvedCatalogSource{Image: &catalogd.ResolvedImageSource{ Ref: "fake/catalog@sha256:fakesha", }}, - ContentURL: "https://fake-url.svc.local/all.json", + URLs: &catalogd.ClusterCatalogURLs{ + Base: "https://fake-url.svc.local/catalogs/catalog-1", + }, }, } }