Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

115 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hops-cli

hops-cli is a Rust CLI for Crossplane development and XR lifecycle workflows.

Overview

This tool supports three related workflows:

  • Local cluster setup on colima or kind
  • Configuration package install/uninstall against the connected cluster
  • XR observe/manage/adopt/orphan workflows for existing infrastructure

For local development, it can also:

  • Install and manage a local cluster backend (colima or kind)
  • Start a local k8s cluster with Crossplane installed via Helm
  • Install the Kubernetes and Helm Crossplane providers
  • Deploy an in-cluster OCI registry (crossplane-system/registry)
  • Build and publish Crossplane configuration packages from an XRD project

Installation

Using ubi

  1. Install ubi:
    Ensure you have ubi installed by running:
    curl --silent --location \
     https://raw.githubusercontent.com/houseabsolute/ubi/master/bootstrap/bootstrap-ubi.sh |
     sh
    
    mkdir -p ~/.ubi/bin
    echo 'export PATH="$HOME/.ubi/bin:$PATH"' >> ~/.zshrc  # or your preferred shell profile
  2. Install vnext with ubi:
    ubi --project hops-ops/hops-cli --in /usr/local/bin --rename-exe hops

Install a specific version:

ubi --project hops-ops/hops-cli --tag vx.x.x --in /usr/local/bin/ --rename-exe hops

See "Releases" for available versions and changenotes.

Prerequisites

  • macOS
  • Rust/Cargo
  • Homebrew
  • docker CLI
  • kubectl
  • helm
  • up (Upbound CLI, used by up project build)
  • aws CLI v2 (used by local aws to export profile credentials)

Note: hops-cli local install installs the selected backend (colima or kind) through Homebrew.

Build

cargo build

If you want static OpenSSL vendoring:

cargo build --features vendored

Usage

hops --help
hops local --help
hops config --help
hops secrets --help
hops validate --help
hops xr --help

Command Areas

hops-cli is organized into a few command groups:

  • local
    • Manage a local control plane (colima, kind, or dory backend), install providers, and bootstrap AWS or GitHub provider auth.
  • config
    • Build, install, reload, and uninstall Crossplane configuration packages against the connected cluster.
  • secrets
    • Initialize secrets config, encrypt and decrypt local secrets, and sync repo-managed secrets to AWS Secrets Manager or GitHub repository secrets.
  • validate
    • Generate configuration manifests from Upbound-format XRD projects for validation workflows.
  • xr
    • Observe existing XR-backed infrastructure and render adoption, management, or orphaning manifests.

Microservice scaffolding previously available as hops service now lives in the standalone distributed CLI (distributed / distributed_cli).

Secrets

hops secrets init sets up local secrets directories, .sops.yaml, and .hops.yaml so plaintext secrets can be encrypted locally and synced to AWS Secrets Manager or GitHub repository secrets.

Typical layout:

secrets/
  aws/
  github/
    _shared/
secrets-encrypted/
  aws/
  github/

Typical config:

secrets:
  plaintext_dir: secrets
  encrypted_dir: secrets-encrypted
  aws:
    path: aws
    region: us-east-2
    tags:
      hops.ops.com.ai/secret: "true"
  github:
    owner: hops-ops
    path: github
    shared_secrets:
      path: _shared
      repos:
        - repo-a
        - repo-b

Encrypt and decrypt operate from the configured roots:

hops secrets encrypt
hops secrets decrypt

AWS sync reads from <plaintext_dir>/<aws.path>:

hops secrets sync aws

AWS rules:

  • A .json file becomes one AWS Secrets Manager secret with the JSON object stored as-is.
  • A directory containing plain files rolls up into one AWS secret. Each filename becomes a key in the JSON object.
  • A .env file is parsed into key/value pairs and stored as one JSON secret.
  • A directory containing a .env file merges those parsed key/value pairs into that directory's rolled-up JSON secret.
  • Secret names are derived from the path relative to the AWS root.
  • --cleanup only works when syncing the full configured AWS root.
  • hops.ops.com.ai/secret=true is always applied to repo-managed AWS secrets.

Examples:

  • secrets/aws/app.json -> AWS secret app
  • secrets/aws/github/token and secrets/aws/github/owner -> AWS secret github
  • secrets/aws/slack/.env with WEBHOOK_URL=... -> AWS secret slack

GitHub sync reads from <plaintext_dir>/<github.path>:

hops secrets sync github

GitHub rules:

  • Each GitHub secret remains a separate GitHub secret. There is no AWS-style roll-up into a single JSON secret.
  • A raw file becomes one GitHub secret.
  • A .json file becomes multiple GitHub secrets, one per top-level key.
  • A .env file becomes multiple GitHub secrets, one per KEY=value entry.
  • Repo-specific secrets come from repo-named paths like secrets/github/repo-a/... or secrets/github/repo-a.json.
  • Shared GitHub secrets come from secrets/github/_shared/... and fan out to the repos listed in secrets.github.shared_secrets.repos or passed with --repo.
  • If a shared secret and a repo-specific secret have the same final name, the repo-specific value wins for that repo.
  • GitHub secret names are normalized by the CLI to a stable format before syncing.

Examples:

  • secrets/github/repo-a/NPM_TOKEN -> GitHub secret NPM_TOKEN in repo-a
  • secrets/github/repo-a/actions.json with {"SLACK_WEBHOOK":"..."} -> GitHub secret SLACK_WEBHOOK in repo-a
  • secrets/github/repo-a/.env with NPM_TOKEN=... -> GitHub secret NPM_TOKEN in repo-a
  • secrets/github/_shared/ORG_TOKEN -> synced to every configured shared target repo

Create a Local Control Plane

# 1) Install the backend (via Homebrew). Defaults to colima on macOS;
#    pass --backend kind to use kind on any docker daemon.
hops local install

# 2) Start local k8s + Crossplane + providers + local registry
hops local start

# 3) Configure AWS provider-family + ProviderConfig from your AWS profile
hops local aws --profile <aws-profile>

# 4) Configure GitHub provider + ProviderConfig from your gh auth login
hops local github --owner <org-or-user>

# 5) Configure Zitadel provider + ProviderConfig from the AuthStack PAT Secret
hops local zitadel --source-context pat-local --domain auth.ops.com.ai

# 6) Install a Crossplane configuration package from an Upbound-format XRD project
hops config install --repo hops-ops/aws-auto-eks-cluster --version v0.11.0

Cluster backends

hops local supports three backends behind the same commands:

  • colima — a VM running dockerd + k3s. macOS/Linux; supports --cpus, --memory, --disk, and hops local resize.
  • kind — cluster nodes as docker containers on any reachable docker daemon: Docker Desktop, colima's dockerd, or CI runners. No VM of its own, so sizing flags don't apply (size the docker daemon instead); requires kind >= v0.27.
  • dorydory stock app: shared Apple Silicon engine + product k3s. Enable Kubernetes in the Dory app (hops does not fork Dory or call dory k8s enable). Package installs use the same in-cluster registry:2 as other backends (Crossplane pulls registry.crossplane-system.svc.cluster.local:5000). Docker push uses the k3s NodePort on the engine docker bridge ({dory-k8s-ip}:30500) because dockerd runs inside the engine — Mac localhost is the wrong plane. The VM is sized in the Dory app, so hops sizing flags don't apply.

Select with the global --backend flag:

hops local start --backend kind

The chosen backend is persisted to ~/.hops/local/backend on a successful start, so later commands (stop, destroy, doctor, package installs) target the same cluster without the flag. Resolution order: --backend flag > persisted choice > existing cluster detection (colima wins) > platform default (macOS: colima, otherwise kind).

Unless --context is given, kubectl commands automatically use the backend's kubeconfig context (colima, kind-hops, or hops-dory), regardless of your current-context.

Using dory

Stock Dory only (brew cask / Dory.app). No hops fork of Dory required.

# 1. Open Dory.app — engine healthy (not "needs attention")
# 2. Enable Kubernetes in the app; wait until the cluster is running
#    (product container is usually named dory-k8s)
# 3. Bootstrap Crossplane + local package registry
hops local start --backend dory

On start/activate, hops:

  • merges stock ~/.kube/dory-config into ~/.kube/config as context hops-dory (override with --name <name> or HOPS_DORY_NAME; persisted in ~/.hops/local/dory-name)
  • runs kubectl config use-context hops-dory
  • creates/uses a docker context of the same name → unix://$HOME/.dory/dory.sock

So you should not need:

export KUBECONFIG=$HOME/.kube/dory-config
export DOCKER_HOST=unix://$HOME/.dory/dory.sock
hops local start --backend dory              # name defaults to hops-dory
hops local start --backend dory --name mine  # custom kube+docker context name

kubectl get nodes          # context hops-dory
docker info                # context hops-dory
hops local doctor
hops local github -o hops-ops
hops config install --path … --backend dory

Alternatively, use kind on Dory's docker socket (no product k3s):

docker context use dory   # product context from Dory.app
hops local start --backend kind

CI: .github/workflows/on-pr-dory-smoke.yaml runs on a self-hosted Apple Silicon Mac labeled hops-dory (opt-in with PR label test-dory or workflow_dispatch). Stock Dory only — no fork build, no Colima sock. Offline runner → job waits. The session is env-only so your desktop defaults never change: DOCKER_HOST=unix://$HOME/.dory/dory.sock, a job-private KUBECONFIG, and HOPS_DORY_DESKTOP=0 (hops skips use-context / docker context switching). No destroy/stop of dory-k8s. After start/doctor/registry, it path-installs the in-repo fixture tests/fixtures/config-smoke (hops config install --path …) and applies a namespaced ConfigMap XR under hops-ci. See the workflow header for runner setup.

Dory architecture (why troubleshooting is different)

Two network planes matter. Mixing them up is the usual failure mode.

Plane Who Where Role
Engine Docker docker CLI via ~/.dory/dory.sock Linux VM (dockerd) build/push images
Cluster kubectl / Crossplane pods k3s inside dory-k8s run control plane + pull packages

Package registry model (same idea as colima/kind, adapted to Dory):

  • Pull (Crossplane): in-cluster Service
    registry.crossplane-system.svc.cluster.local:5000 over HTTPS
  • Push (docker on the engine): k3s NodePort on the docker bridge
    {dory-k8s-ip}:30500 (not Mac localhost:30500)
  • TLS: hops generates a self-signed CA/server cert (Secret hops-local-registry-tls) and patches Crossplane to trust that CA. Plain HTTP fails package unpack (http: server gave HTTP response to HTTPS client).

Do not put host.dory.internal in Crossplane package refs. That name exists on the node /etc/hosts, not in pod CoreDNS, and is the wrong plane for Crossplane's package manager.

Dory troubleshooting

Engine won't start / thrash / HV_BAD_ARGUMENT (big Macs)

The failure we hit in practice: on a large laptop (e.g. 128 GB host RAM), Dory's UI Recommended / host-scaled default for guest engine memory was ~half of host RAM → 64 GB (DORYD_MEMORY_MB=65536). That is not "you need 64 GB of containers" — it is an aggressive ceiling. On Apple Silicon, Hypervisor.framework often rejects creating a VM that large (HV_BAD_ARGUMENT), so the engine never stays healthy and the UI looks broken even though a 4 GB engine works fine.

# Pin sane resources (4 GiB / 4 CPUs is enough for hops local)
defaults write com.pythonxi.Dory dory.engineMemoryMB -int 4096
defaults write com.pythonxi.Dory dory.engineCPUCount -int 4

# Confirm the LaunchAgent is not still on 65536:
launchctl print "gui/$(id -u)/dev.dory.doryd" 2>/dev/null | grep DORYD_MEMORY
# Live engine cmdline should show --mem-mb 4096, not 65536:
ps aux | grep 'dory-hv engine' | grep -v grep

In the Dory app Resources panel: set memory to ~4 GB (8 GB is usually fine too). Do not apply Recommended if it offers tens of GB on a high-RAM Mac.

Then fully restart the engine (quit Dory, ensure no thrashing doryd/dory-hv, reopen or dory engine wake). Once guest RAM is modest, the rest of hops local is ordinary.

Docker socket path

Stock Docker API socket is:

unix://$HOME/.dory/dory.sock

There is no ~/.dory/engine.sock for the host Docker API. hops uses dory.sock only. Prefer the docker context hops creates (hops-dory) over manual DOCKER_HOST.

Kubernetes missing / no dory-k8s container

k3s is product-owned. hops does not run dory k8s enable.

  1. Install the Kubernetes component if needed: dory component install kubernetes
  2. Enable Kubernetes in the Dory app UI
  3. Wait until a dory-k8s container is running: docker ps (with context hops-dory)
  4. Re-run hops local start --backend dory

k ctx has no dory / hops-dory entry

Stock Dory writes ~/.kube/dory-config (context often named default). hops merges that into ~/.kube/config as hops-dory on activate/start. If the merge is missing:

hops local doctor --backend dory
kubectl config get-contexts   # expect hops-dory
kubectl config use-context hops-dory

Configuration Installed=False / HTTPS error

http: server gave HTTP response to HTTPS client

Crossplane always pulls packages with HTTPS. The local registry must be TLS (hops sets this up). If you have an old HTTP-only registry Deployment:

kubectl -n crossplane-system delete deploy registry
kubectl -n crossplane-system delete secret hops-local-registry-tls
hops local start --backend dory    # recreates TLS secret + registry + CA patch

docker push to localhost:30500 fails (connection refused / HTTPS to HTTP)

With the docker context pointed at Dory, localhost is the engine VM, not the Mac. hops pushes to {dory-k8s container IP}:30500 and marks the engine docker bridge as an insecure registry for that self-signed TLS endpoint. Check:

docker context show          # hops-dory
hops local doctor            # "package push registry reachable (…:30500)"

Do not rely on Mac kubectl port-forward for engine-side docker push.

Engine docker broken after daemon.json / dockerd kill

Prefer Dory's own recovery:

dory repair dockerd --apply
dory engine wake
dory readiness

Avoid raw kill of dockerd inside the guest unless you are prepared to wait for dory repair / LaunchAgent recovery (live-restore helps but is not magic).

Useful diagnostics

dory doctor
dory readiness
hops local doctor --backend dory
docker context show
kubectl config current-context
kubectl get configuration,provider -A
kubectl -n crossplane-system get deploy,svc,secret | grep -E 'registry|crossplane|hops-local'

Local provider setup and auth

hops local aws, hops local github, and hops local zitadel install the provider package and bootstrap auth into a local control plane. The exception is --refresh, which updates credentials only.

AWS auth

hops local aws installs the AWS provider package and uses your AWS CLI configuration to generate credentials for it.

# Use an explicit AWS profile
hops local aws --profile hops

# Refresh only the Secret credentials without re-applying the Provider or ProviderConfig
hops local aws --profile hops --refresh

How it works:

  • Resolves the profile in this order: --profile, AWS_PROFILE, AWS_DEFAULT_PROFILE, then interactive prompt.
  • Runs aws configure export-credentials --format process.
  • If the selected profile needs AWS SSO login, it runs aws sso login --profile <profile> and retries once.
  • Applies the AWS provider package unless --refresh is used.
  • Writes the generated credentials into a Kubernetes Secret, defaulting to default/aws-creds.
  • Applies an AWS ProviderConfig named default unless --refresh is used.
  • Supports overrides for namespace, Secret name, ProviderConfig name, provider name, and provider package.

GitHub auth

hops local github installs the GitHub provider package and uses your GitHub CLI login to generate credentials for it.

# Use an explicit owner
hops local github --owner hops-ops

# Refresh only the Secret credentials without re-applying the Provider or ProviderConfig
hops local github --owner hops-ops --refresh

How it works:

  • Resolves the owner in this order: --owner, GH_OWNER, GITHUB_OWNER, then interactive prompt.
  • Uses your current gh auth token.
  • If gh is not authenticated, it runs gh auth login and retries once.
  • Applies the GitHub provider package unless --refresh is used.
  • Writes the generated credentials into a Kubernetes Secret, defaulting to default/github-creds.
  • Applies a GitHub ProviderConfig named default unless --refresh is used.
  • Supports overrides for namespace, Secret name, ProviderConfig name, provider name, and provider package.

Zitadel auth

hops local zitadel installs the Zitadel provider package and creates a Zitadel ProviderConfig for consumer stacks that need to author Zitadel resources from the local control plane.

# Read the AuthStack iam-admin PAT from a target cluster and create default/zitadel-credentials + ProviderConfig/default
hops local zitadel --source-context pat-local --domain auth.ops.com.ai

# Use an explicit token instead of reading the target cluster Secret
ZITADEL_ACCESS_TOKEN=<pat> hops local zitadel --domain auth.ops.com.ai

# Refresh only the Secret credentials without re-applying the Provider or ProviderConfig
hops local zitadel --source-context pat-local --domain auth.ops.com.ai --refresh

How it works:

  • Resolves the access token in this order: --access-token, ZITADEL_ACCESS_TOKEN, then the source cluster Secret.
  • Defaults the source Secret to pat-local/zitadel/iam-admin-pat key pat.
  • Writes the generated credentials JSON into a Kubernetes Secret, defaulting to default/zitadel-credentials.
  • Applies a Zitadel ProviderConfig named default unless --refresh is used.
  • Supports overrides for namespace, Secret name, ProviderConfig name, provider name, provider package, source context, source namespace, source Secret, source key, domain, port, and insecure.

Config packages

config install and config uninstall operate on the currently connected Kubernetes cluster.

There are two different config install modes:

  • Source-build mode via --path or --repo builds an Upbound-format XRD project locally, pushes the package through the local registry flow, and is intended for a local control plane started with hops local start.
  • Remote-package mode via --repo ... --version ... skips the build and applies a pinned package reference directly, so it can work against non-local connected clusters too.

Common install flows:

# Build from the current directory when it is an Upbound-format XRD project
hops config install

# Build from an explicit local Upbound-format XRD project path
hops config install --path /path/to/project

# Install from a GitHub repo; interactive TTY runs ask whether to build from source
# or use a published version
hops config install --repo hops-ops/aws-auto-eks-cluster

# Force a source reload before re-applying
hops config install --repo hops-ops/aws-auto-eks-cluster --reload

# Set spec.skipDependencyResolution=true on the generated Configuration
hops config install --path /path/to/project --skip-dependency-resolution

# Apply a pinned remote package directly from ghcr.io
hops config install --repo hops-ops/aws-auto-eks-cluster --version v0.11.0

Common uninstall flows:

# Remove by explicit configuration name
hops config uninstall --name hops-ops-aws-auto-eks-cluster

# Remove by repo slug
hops config uninstall --repo hops-ops/aws-auto-eks-cluster

# Remove configurations derived from local build artifacts
hops config uninstall --path /path/to/project

Notes:

  • --reload only applies to source installs: --path or --repo without --version.
  • --skip-dependency-resolution sets spec.skipDependencyResolution=true on the generated Configuration.
  • config install --repo ... now prompts in interactive terminals to choose between cloning/building from source or applying a published package version. Published-version prompts suggest the latest discovered tag by default and still accept arbitrary tags such as pr-<gitsha>.
  • Non-interactive config install --repo ... keeps the previous default behavior and builds from source.
  • config install --repo ... --version ... skips clone/build and applies the remote package directly.
  • config uninstall --repo ... derives the configuration name as <org>-<repo>.

Commands

  • local install
    • Runs brew install colima.
  • local reset
    • Runs colima kubernetes reset.
  • local start [--bootstrap]
    • Brings up the selected backend cluster (colima / kind / dory)
    • If Crossplane, k8s+helm providers, and the package registry are already Healthy/Available, skips helm repo update/upgrade and bootstrap reapply (fast resume). Pass --bootstrap to force a full helm upgrade + reapply.
    • Cold path: installs Crossplane, applies bootstrap/ DRCs/providers/PCs, deploys the local HTTPS package registry, wires node/engine registry trust
  • local stop
    • Runs colima stop.
  • local destroy
    • Runs colima delete --force.
  • local uninstall
    • Prompts for confirmation, then runs brew uninstall colima.
  • config install [--path <PATH>] [--reload]
    • Targets the currently connected Kubernetes cluster
    • Source-build mode intended for a local control plane because it depends on the local registry flow
    • Runs up project build in PATH (defaults to current directory)
    • Loads generated .uppkg artifacts from <PATH>/_output
    • Pushes package images to the registry exposed at localhost:30500
    • Applies Crossplane Configuration resources pointing at registry.crossplane-system.svc.cluster.local:5000/...
    • Supports --skip-dependency-resolution
  • config install --repo <org/repo> [--reload]
    • Interactive terminals prompt for install mode: source build or published version
    • Published-version installs suggest the latest discovered tag by default and accept custom tags such as pr-<gitsha>
    • Non-interactive runs and --reload continue to use the source-build flow
    • Source-build mode is intended for a local control plane because it depends on the local registry flow
    • Source builds use local repo cache at ~/.hops/local/repo-cache/<org>/<repo>
    • Source builds clone on first use, then fetch/pull on subsequent runs
    • Source builds run the same build/load/push/apply flow as --path
  • --reload
    • Forces source-based config install (--path or --repo without --version) to delete existing ConfigurationRevision resources and matching Function/FunctionRevision package resources from the same sources, then re-apply the Configuration
    • Useful when re-running a config and you want Crossplane to re-create the current revision from source
  • config install --repo <org/repo> --version <tag>
    • Remote-package mode that can target any connected cluster
    • Skips clone/build and applies Configuration with package ghcr.io/<org>/<repo>:<tag>
    • Uses configuration name <org>-<repo> (for example hops-ops-aws-auto-eks-cluster)
    • Does not support --reload
    • Supports --skip-dependency-resolution
  • config uninstall --name <configuration-name>
    • Deletes the target Configuration
    • Waits for package lock reconciliation
    • Prunes orphaned Configuration/Function/Provider packages and revisions no longer present in lock
    • Prunes orphaned ImageConfig rewrites for removed render functions
  • config uninstall --repo <org/repo>
    • Targets configuration name <org>-<repo>
    • If cached repo exists at ~/.hops/local/repo-cache/<org>/<repo>, derives source hints from it for additional package pruning
  • config uninstall --path <PATH>
    • Derives target configuration names from <PATH>/_output/*.uppkg image tags
    • Also derives package sources from those artifacts and prunes matching package resources (including Functions) if they remain
  • local aws [--profile <AWS_PROFILE>]
    • Exports temporary AWS credentials with aws configure export-credentials --format process
    • Uses profile resolution order: --profile -> AWS_PROFILE -> AWS_DEFAULT_PROFILE -> interactive prompt
    • If AWS SSO token is missing/expired, runs aws sso login --profile <profile> and retries once
    • Applies xpkg.crossplane.io/crossplane-contrib/provider-family-aws:v2.4.0
    • Waits for providerconfigs.aws.m.upbound.io CRD to exist
    • Applies a Secret (aws-creds) and AWS ProviderConfig (default) in namespace default
    • --refresh updates only the Secret credentials and skips Provider/ProviderConfig apply
    • Supports overrides via --namespace, --secret-name, --provider-config-name, --provider-name, and --provider-package
  • local github [--owner <ORG_OR_USER>]
    • Exports your current GitHub CLI token with gh auth token
    • Uses owner resolution order: --owner -> GH_OWNER -> GITHUB_OWNER -> interactive prompt with your authenticated gh login as the default
    • If GitHub CLI is not authenticated, runs gh auth login and retries once
    • Applies xpkg.crossplane.io/crossplane-contrib/provider-upjet-github:v0.19.0
    • Waits for providerconfigs.github.m.upbound.io CRD to exist
    • Applies a Secret (github-creds) and GitHub ProviderConfig (default) in namespace default
    • --refresh updates only the Secret credentials and skips Provider/ProviderConfig apply
    • Supports overrides via --namespace, --secret-name, --provider-config-name, --provider-name, and --provider-package
  • validate generate-configuration [--path <PATH>] [--api-path <APIS_PATH>]
    • Reads <PATH>/upbound.yaml and writes <APIS_PATH>/configuration.yaml
    • Auto-detects --api-path via apis/*/definition.yaml when omitted
    • Ensures apis/**/configuration.yaml is present in <PATH>/.gitignore (unless --no-gitignore-update)
  • xr observe --kind <KIND> --name <NAME> --namespace <NAMESPACE> --aws-region <REGION>
    • Generates an observe-only XR manifest for an existing resource
    • Loads the live XR from the cluster when present
    • Enriches the manifest with live AWS discovery for supported XR kinds such as AutoEKSCluster and Network
    • Supports --output and --apply
  • xr adopt --kind <KIND> --name <NAME> --namespace <NAMESPACE>
    • Lists managed resources that belong to the XR and renders metadata patches needed for adoption
    • For AutoEKSCluster, uses the composite-specific label hops.ops.com.ai/autoekscluster=<name>
    • Only emits patches for resources whose external name is missing or blank and can be resolved for that kind
    • Supports --apply, --output, and --recursive
  • xr manage --kind <KIND> --name <NAME> --namespace <NAMESPACE>
    • Generates the final managed XR manifest from an observed or adopted XR already in the cluster
    • Supports --output and --apply
  • xr orphan --kind <KIND> --name <NAME> --namespace <NAMESPACE>
    • Renders managed-resource patches that remove Delete from management policies
    • Supports --apply and --output

XR workflow

Typical reclaim flow:

# 1) Observe the existing resource into an XR manifest
hops xr observe --kind AutoEKSCluster --name pat-local --namespace default --aws-region us-east-2 --output observed.yaml

# 2) Apply the observe XR if desired
kubectl apply -f observed.yaml

# 3) Render and apply adoption patches for the next set of managed resources
hops xr adopt --kind AutoEKSCluster --name pat-local --namespace default --apply

# 4) Repeat adopt until no more patches are needed, or use --recursive
hops xr adopt --kind AutoEKSCluster --name pat-local --namespace default --recursive --apply

# 5) Convert the XR into a managed manifest
hops xr manage --kind AutoEKSCluster --name pat-local --namespace default --output managed.yaml

Notes:

  • xr adopt only patches resources it can identify for the selected XR kind.
  • A blank crossplane.io/external-name is treated as missing.
  • AutoEKSCluster adoption currently resolves identities for supported managed kinds such as IAM attachments and KMS keys.

Logging

Set LOG_LEVEL to control output (default: info):

LOG_LEVEL=debug hops local start

Development

cargo test

About

hops, like in basketball, but for ops - CLI

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages