Skip to content

Commit

Permalink
Address reviewer comments
Browse files Browse the repository at this point in the history
Signed-off-by: Per Goncalves da Silva <[email protected]>
  • Loading branch information
Per Goncalves da Silva committed Sep 13, 2024
1 parent c29c762 commit e8963a1
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 36 deletions.
176 changes: 176 additions & 0 deletions hack/tools/catalogs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Hack Catalog Tools

This directory contains scripts that automate some of the tasks related to catalog interaction and bundle installation.

---
> [!WARNING]
> These scripts are intended to help users navigate the catalog and produce installation RBAC until reliable tooling is available for OLM v1,
> and to document the process in code for contributors. These scripts are not officially supported.
> They are not meant to be used in production environments.
---

### Prerequisites

To execute the scripts, the following tools are required:

* [jq](https://jqlang.github.io/jq/) to filter catalog data
* [kubectl](https://kubernetes.io/docs/reference/kubectl/) to interact with the cluster running OLM v1
* [wget](https://www.gnu.org/software/wget/) to download the catalog data
* A container runtime, such as [podman](https://podman.io/) or [docker](https://www.docker.com/) to interact with bundle images.

#### Container Runtime

By default, the scripts use `podman` or `docker` as the container runtime.
If you use another container runtime, set the `CONTAINER_RUNTIME` environment variable to the path of the container runtime binary.

### Tools

---
> [!NOTE]
> All examples assume that the current working directory is the `hack/tools/catalogs` directory.
---

#### download-catalog

Download a catalog from an unpacked ClusterCatalog running on a cluster reachable by `kubectl`.

Example:

```terminal
# Download the catalog from the operatorhubio ClusterCatalog
./download-catalog operatorhubio
```

The downloaded catalog is saved to <catalog-name>-catalog.json in the current directory.

#### list-compatible-bundles

List (potential) OLM v1 compatible bundles from the catalog.

Not all registry+v1 bundles made for OLM v0 are compatible with OLM v1.
Compatible bundles must meet the following criteria:
* Support for the 'AllNamespaces' install mode
* No webhooks
* No dependencies on other packages of GVKs
* The operator does not make use of OLM v0's [`OperatorCondition`](https://olm.operatorframework.io/docs/concepts/crds/operatorcondition/) API

<!---
TODO: Update link to OLM v1 limitations doc when it is available.
-->
For more information, see [OLM v1 limitations](../../../docs/refs/olm-v1-limitations.md).

For some bundles, some of this criteria can only be determined by inspecting the contents bundle image. The script will return all bundles that are potentially compatible.

Examples:

``` terminal
# List (potentially) OLM v1 compatible bundles from the operatorhubio catalog
./list-compatible-bundles < operatorhubio-catalog.json
```

``` terminal
# List (potentially) OLM v1 compatible bundles that contain 'argco' in the package name
# -r can be used with any regex supported by jq
./list-compatible-bundles -r 'argocd' < operatorhubio-catalog.json
```

#### find-bundle-image

Find the image for a bundle in the catalog.

Example:

``` terminal
# Get the image for the argocd-operator v0.6.0 bundle from the operatorhubio catalog
./find-bundle-image argocd-operator 0.6.0 < operatorhubio-catalog.json
```

#### unpack-bundle

Unpack a bundle image to a directory.

Example:

``` terminal
# Unpack the argocd-operator v0.6.0 bundle image to a temporary directory
./unpack-bundle quay.io/operatorhubio/argocd-operator@sha256:d538c45a813b38ef0e44f40d279dc2653f97ca901fb660da5d7fe499d51ad3b3
```

``` terminal
# Unpack the argocd-operator v0.6.0 bundle image to a specific directory
./unpack-bundle quay.io/operatorhubio/argocd-operator@sha256:d538c45a813b38ef0e44f40d279dc2653f97ca901fb660da5d7fe499d51ad3b3 -o argocd-manifests
```

#### is-bundle-supported

Check if a bundle is supported by OLM v1 by inspecting the unpacked bundle manifests.

<!---
TODO: Update link to OLM v1 limitations doc when it is available.
-->
For more information on bundle support, see [OLM v1 limitations](../../../docs/refs/olm-v1-limitations.md).

Example:

``` terminal
# Check if the argocd-operator v0.6.0 bundle from the operatorhubio catalog is supported by OLM v1
./is-bundle-supported argocd-manifests
```

``` terminal
# Find bundle image, unpack, and verify support in one command
./find-bundle-image argocd-operator 0.6.0 < operatorhubio-catalog.json | ./unpack-bundle | ./is-bundle-supported
```

#### generate-manifests

Generate RBAC or installation manifests for a bundle. The generated manifests can be templates or fully rendered manifests.

The following options can be used to override resource naming defaults:
-n <namespace> Namespace where the extension is installed
-e <cluster-extension-name> - Name of the extension
-cr <cluster-role-name> - Name of the cluster role
-r <role-name> - Name of the role
-s <service-account-name> - Name of the service account
--template - Generate template manifests

Default resource name format:
* Namespace: <cluster-extension-name>-system
* Extension name: <package-name>
* ClusterRole name: <service-account-name>-cluster-role
* Role name: <service-account-name>-installer-role
* ServiceAccount name: <package-name>-installer
* ClusterRoleBinding name: <cluster-role-name>-binding
* RoleBinding name: <role-name>-binding

Use `--template` to generate templated manifests that can be customized before applying to the cluster.
Template manifests will contain the following template variables:

Template Variables:
* `${NAMESPACE}` - Namespace where the extension is installed
* `${EXTENSION_NAME}` - Name of the extension
* `${CLUSTER_ROLE_NAME}` - Name of the cluster role
* `${ROLE_NAME}` - Name of the role
* `${SERVICE_ACCOUNT_NAME}` - Name of the service account

Examples:

``` terminal
# Generate installation manifests for the argocd-operator v0.6.0 bundle from the operatorhubio catalog
./generate-manifests install argocd-operator 0.6.0 < operatorhubio-catalog.json
```

``` terminal
# Generate templated installation manifests for the argocd-operator v0.6.0 bundle from the operatorhubio catalog
generate-manifests install argocd-operator 0.6.0 --template < operatorhubio-catalog.json
```

``` terminal
# Generate RBAC manifests for the argocd-operator v0.6.0 bundle from the operatorhubio catalog
generate-manifests rbac argocd-operator 0.6.0 < operatorhubio-catalog.json
```

``` terminal
# Generate templated RBAC manifests for the argocd-operator v0.6.0 bundle from the operatorhubio catalog
generate-manifests rbac argocd-operator 0.6.0 --template < operatorhubio-catalog.json
```
41 changes: 32 additions & 9 deletions hack/tools/catalogs/download-catalog
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
SCRIPT_ROOT=$(dirname "$(realpath "$0")")
source "${SCRIPT_ROOT}/lib/utils.sh"

# Constants
SERVICE_NAMESPACE="olmv1-system"
SERVICE_NAME="catalogd-catalogserver"
LOCAL_PORT=8001
SERVICE_PORT=443 # Assuming the service uses HTTPS on port 443
# Check required tools are installed
assert-commands kubectl jq wget

# ClusterCatalog coordinates
: "${CATALOGD_CATALOGD_SERVICE_NAMESPACE:=olmv1-system}"
: "${CATALOGD_SERVICE_NAME:=catalogd-catalogserver}"
: "${CATALOGD_SERVICE_PORT:=443}" # Assumes the service uses HTTPS on port 443
: "${CATALOGD_LOCAL_SERVICE_PORT:=8001}"

echo "Namespace: $CATALOGD_CATALOGD_SERVICE_NAMESPACE"
echo "Service Name: $CATALOGD_SERVICE_NAME"
echo "Service Port: $CATALOGD_SERVICE_PORT"
echo "Local Service Port: $CATALOGD_LOCAL_SERVICE_PORT"

# Display usage
usage() {
Expand Down Expand Up @@ -53,14 +61,29 @@ if [ -z "$CONTENT_URL" ]; then
fi

# Start port forwarding
echo "Starting kubectl port-forward to $SERVICE_NAME on port $LOCAL_PORT..."
kubectl port-forward -n "$SERVICE_NAMESPACE" svc/"$SERVICE_NAME" $LOCAL_PORT:$SERVICE_PORT &>/dev/null &
echo "Starting kubectl port-forward to $CATALOGD_SERVICE_NAME on port $CATALOGD_LOCAL_SERVICE_PORT..."
kubectl port-forward -n "$CATALOGD_CATALOGD_SERVICE_NAMESPACE" svc/"$CATALOGD_SERVICE_NAME" "$CATALOGD_LOCAL_SERVICE_PORT:$CATALOGD_SERVICE_PORT" &>/dev/null &
PORT_FORWARD_PID=$!
sleep 2 # Wait for the port-forwarding to start

# Poll the service until it responds or timeout after 30 seconds
timeout=30
while ! curl -s "http://localhost:${CATALOGD_LOCAL_SERVICE_PORT}" >/dev/null; do
timeout=$((timeout - 1))
if [ $timeout -le 0 ]; then
echo "Port forwarding failed to start within 30 seconds."
kill $PORT_FORWARD_PID
exit 1
fi
sleep 1
done

# Modify the contentURL to hit localhost:<port>
LOCAL_CONTENT_URL=$(echo "$CONTENT_URL" | sed "s|https://[^/]*|https://localhost:$LOCAL_PORT|")
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"
echo "Using local port: $CATALOGD_LOCAL_SERVICE_PORT"
echo "Using local content URL: $LOCAL_CONTENT_URL"

# shellcheck disable=SC2001
# Download the catalog using wget
echo "Downloading catalog from $LOCAL_CONTENT_URL..."
wget --no-check-certificate "$LOCAL_CONTENT_URL" -O "${CATALOG_NAME}-catalog.json"
Expand Down
3 changes: 3 additions & 0 deletions hack/tools/catalogs/find-bundle-image
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ SCRIPT_ROOT=$(dirname "$(realpath "$0")")
source "${SCRIPT_ROOT}/lib/bundle.sh"
source "${SCRIPT_ROOT}/lib/utils.sh"

# Check required tools are installed
assert-commands jq

usage() {
print-banner
echo ""
Expand Down
38 changes: 21 additions & 17 deletions hack/tools/catalogs/generate-manifests
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,33 @@ source "${SCRIPT_ROOT}/lib/unpack.sh"
source "${SCRIPT_ROOT}/lib/collect-rbac.sh"
source "${SCRIPT_ROOT}/lib/utils.sh"

# Set the container runtime, default to docker
export CONTAINER_RUNTIME=${CONTAINER_RUNTIME:-docker}
# Check there is a container runtime (podman, or docker)
# If neither are found, check CONTAINER_RUNTIME is set and exists in PATH
assert-container-runtime

# Check required tools are installed
assert-commands jq

function usage() {
print-banner
echo ""
echo "Usage:"
echo ""
echo "Generate installation manifests"
echo "$0 install <package-name> <package-version> [-n namespace] [-e cluster-extension-name] [-cr cluster-role-name] [-r role-name] [-s service-account-name] [--use-defaults]"
echo "$0 install <package-name> <package-version> [-n namespace] [-e cluster-extension-name] [-cr cluster-role-name] [-r role-name] [-s service-account-name] [--template]"
echo ""
echo "Generate RBAC manifests"
echo "$0 rbac <package-name> <package-version> [-n namespace] [-e cluster-extension-name] [-cr cluster-role-name] [-r role-name] [-s service-account-name] [--use-defaults]"
echo "$0 rbac <package-name> <package-version> [-n namespace] [-e cluster-extension-name] [-cr cluster-role-name] [-r role-name] [-s service-account-name] [--template]"
echo ""
echo "Generate installation or RBAC manifests for a registry+v1 package given an FBA catalog in stdin"
echo "Generate installation or RBAC manifests for a registry+v1 package given an FBC catalog in stdin"
echo ""
echo "Options:"
echo " -n <namespace> - Namespace where the extension is installed"
echo " -e <cluster-extension-name> - Name of the extension"
echo " -cr <cluster-role-name> - Name of the cluster role"
echo " -r <role-name> - Name of the role"
echo " -s <service-account-name> - Name of the service account"
echo " --use-defaults - Use default resource names"
echo " --template - Generate template manifests"
echo ""
echo "Template Variables:"
echo " * \${NAMESPACE} - Namespace where the extension is installed"
Expand All @@ -52,16 +56,16 @@ function usage() {
echo ""
echo "Examples:"
echo " # Generate installation manifests for the argocd-operator package"
echo " $0 install argocd-operator 0.6.0 --use-defaults < operatorhubio-catalog.json"
echo " $0 install argocd-operator 0.6.0 < operatorhubio-catalog.json"
echo ""
echo " # Generate RBAC manifests for the argocd-operator package"
echo " $0 rbac argocd-operator 0.6.0 --use-defaults < operatorhubio-catalog.json"
echo " $0 rbac argocd-operator 0.6.0 < operatorhubio-catalog.json"
echo ""
echo " # Generate templated installation manifests for the argocd-operator package"
echo " $0 install argocd-operator 0.6.0 < operatorhubio-catalog.json"
echo " $0 install argocd-operator 0.6.0 --template < operatorhubio-catalog.json"
echo ""
echo " # Generate templated RBAC manifests for the argocd-operator package"
echo " $0 rbac argocd-operator 0.6.0 < operatorhubio-catalog.json"
echo " $0 rbac argocd-operator 0.6.0 --template < operatorhubio-catalog.json"
echo ""
echo "WARNING: This script is a stopgap solution until proper tools are available in OLMv1 - it is not guaranteed to work with all packages."
}
Expand All @@ -79,12 +83,12 @@ export PACKAGE_VERSION=$3

# Initialize environment variables with template defaults
export NAMESPACE="\${NAMESPACE}"
export EXTENSION_NAME="\${EXTENSION-NAME}"
export EXTENSION_NAME="\${EXTENSION_NAME}"
export CLUSTER_ROLE_NAME="\${CLUSTER_ROLE_NAME}"
export ROLE_NAME="\${ROLE_NAME}"
export SERVICE_ACCOUNT_NAME="\${SERVICE_ACCOUNT_NAME}"
export DEBUG=false
use_defaults=false
template=false

# Parse optional arguments
shift 3
Expand Down Expand Up @@ -112,8 +116,8 @@ while [[ $# -gt 0 ]]; do
export SERVICE_ACCOUNT_NAME="$2"
shift 2
;;
--use-defaults)
use_defaults=true
--template)
template=true
shift
;;
--debug)
Expand All @@ -128,9 +132,9 @@ while [[ $# -gt 0 ]]; do
esac
done

# Apply default values only to unset parameters if --use-defaults is set
if [ "$use_defaults" = true ]; then
[ "$EXTENSION_NAME" == "\${EXTENSION-NAME}" ] && export EXTENSION_NAME="${PACKAGE_NAME}"
# Apply default values only to unset parameters if --template is not set
if [ "$template" = false ]; then
[ "$EXTENSION_NAME" == "\${EXTENSION_NAME}" ] && export EXTENSION_NAME="${PACKAGE_NAME}"
[ "$NAMESPACE" == "\${NAMESPACE}" ] && export NAMESPACE="${EXTENSION_NAME}-system"
[ "$SERVICE_ACCOUNT_NAME" == "\${SERVICE_ACCOUNT_NAME}" ] && export SERVICE_ACCOUNT_NAME="${PACKAGE_NAME}-installer"
[ "$CLUSTER_ROLE_NAME" == "\${CLUSTER_ROLE_NAME}" ] && export CLUSTER_ROLE_NAME="${SERVICE_ACCOUNT_NAME}-cluster-role"
Expand Down
6 changes: 4 additions & 2 deletions hack/tools/catalogs/is-bundle-supported
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ source "${SCRIPT_ROOT}/lib/unpack.sh"
source "${SCRIPT_ROOT}/lib/collect-rbac.sh"
source "${SCRIPT_ROOT}/lib/utils.sh"

# Check required tools are installed
assert-commands jq

usage() {
print-banner
echo ""
echo "Usage: $0 <manifest_dirn>"
echo "Usage: $0 <manifest_dir>"
echo ""
echo "Check if a bundle is supported by OLM v1 given a bundle manifest directory"
echo ""
Expand All @@ -32,7 +35,6 @@ else
fi

# Check the bundle is supported
echo "Checking if bundle is supported by OLM v1" >&2
assert-bundle-supported "${manifest_dir}"

echo "Bundle is supported by OLM v1" >&2
Expand Down
3 changes: 3 additions & 0 deletions hack/tools/catalogs/lib/bundle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ function get-bundle-image(){
function is-all-namespace-mode-enabled() {
local csv="${1}"
local valid
# Note: The 'and true' is to ensure that the expression evaluates to true or false
# Without it, yq will return the matched value. This is done for succinctness. Without the 'and true',
# the same behavior could be achieved by checking if the output is non-empty.
valid=$(yq eval '(.spec.installModes[] | select(.type == "AllNamespaces" and .supported == true)) and true' "${csv}")
echo "${valid}"
}
Expand Down
Loading

0 comments on commit e8963a1

Please sign in to comment.