diff --git a/Makefile b/Makefile index cb1ce743de2..ce4b793f569 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,22 @@ generate-charts: build ## Re-generate the helm chart testdata and docs samples (cd docs/book/src/cronjob-tutorial/testdata/project && make build-installer && ../../../../../../bin/kubebuilder edit --plugins=helm/v2-alpha) (cd docs/book/src/multiversion-tutorial/testdata/project && make build-installer && ../../../../../../bin/kubebuilder edit --plugins=helm/v2-alpha) +.PHONY: update-demo +update-demo: ## Record and update the Kubebuilder demo using Asciinema + @./scripts/demo/generate-demo.sh + +.PHONY: setup-demo-cluster +setup-demo-cluster: ## Set up Kind cluster for Kubebuilder demo + @./scripts/demo/setup-kind.sh + +.PHONY: clean-demo +clean-demo: ## Clean up the demo Kind cluster and temporary directories + @echo "Cleaning up demo cluster..." + @kind delete cluster --name kubebuilder-demo || echo "Demo cluster was not found or already deleted" + @echo "Cleaning up temporary demo directories..." + @rm -rf /tmp/kubebuilder-demo-project /tmp/kb-demo-recording + @echo "Demo cleanup completed" + .PHONY: check-docs check-docs: ## Run the script to ensure that the docs are updated ./hack/docs/check.sh diff --git a/scripts/demo/README.md b/scripts/demo/README.md index 96f6fe6e4a1..35a31dc8818 100644 --- a/scripts/demo/README.md +++ b/scripts/demo/README.md @@ -1,33 +1,116 @@ -This directory contains scripts to run a quick demo of Kubebuilder. +# Kubebuilder Demo -Steps to run demo: +This directory contains scripts to run a comprehensive demo of Kubebuilder features with a local Kind cluster. + +## Quick Demo (Manual) + +To run the demo manually: ```sh mkdir /tmp/kb-demo cd /tmp/kb-demo -DEMO_AUTO_RUN=1 ./run.sh +DEMO_AUTO_RUN=1 /path/to/kubebuilder/scripts/demo/run.sh +``` + +## Automated Demo Recording + +To automatically record and update the demo using Asciinema: +```sh +# From the root of the Kubebuilder repository +make update-demo ``` -Instructions for producing the demo movie: +This will: +1. Check for required dependencies (asciinema, svg-term, kind, kubectl) +2. Set up a Kind cluster for the demo +3. Record the demo session automatically +4. Convert the recording to SVG format +5. Update the demo file in `docs/gif/kb-demo.${VERSION}.svg` +6. Clean up temporary files + +### Generate Custom Demos + +The script supports generating multiple demo variations: ```sh +# Generate the default kb-demo +./scripts/demo/generate-demo.sh + +# Generate a custom demo with a different name +./scripts/demo/generate-demo.sh my-custom-demo + +# Generate a custom demo using a different script +./scripts/demo/generate-demo.sh advanced-demo ./path/to/custom-script.sh + +# Show help +./scripts/demo/generate-demo.sh --help +``` + +Custom demos will be saved to `docs/gif/${DEMO_NAME}.${VERSION}.svg` and won't automatically update the README (you'll need to reference them manually). + +## Setup Demo Cluster Only + +If you just want to set up the Kind cluster for testing: + +```sh +make setup-demo-cluster +``` + +## Clean Up Demo Cluster + +To remove the demo Kind cluster when done: + +```sh +make clean-demo +``` + +## Prerequisites for Recording + +- `kind`: For creating local Kubernetes clusters +- `kubectl`: For interacting with Kubernetes +- `asciinema`: For recording terminal sessions +- `svg-term`: For converting recordings to SVG (requires Node.js/npm) + +## What the Demo Shows + +The current demo showcases: + +1. **Cluster Setup**: Creates a local Kind cluster for testing +2. **Installation**: Installing Kubebuilder from scratch +3. **Project Initialization**: Creating a new operator project +4. **API Creation**: Creating APIs with validation markers +5. **Plugin System**: Using the deploy-image plugin +6. **Modern Features**: + - Validation markers (`+kubebuilder:validation`) + - Multiple APIs in one project + - Generated CRDs with OpenAPI schemas + - Sample resource management +7. **Development Workflow**: Install CRDs, apply samples, run controller +8. **Cluster Integration**: Full integration with Kubernetes cluster + +## Manual Recording Instructions (Legacy) + +If you prefer to record manually: + +```sh +# Set up Kind cluster first +./scripts/demo/setup-kind.sh # Create temporary directory mkdir /tmp/kb-demo cd /tmp/kb-demo -asciinema rec -/scripts/demo/run.sh - -# After each step, press to proceed to the next step +# Start recording +asciinema rec --title "Kubebuilder Demo" kb-demo.cast - to terminate the script - to terminate the asciinema recording - to save the recording locally +# Run the demo script +DEMO_AUTO_RUN=1 /path/to/kubebuilder/scripts/demo/run.sh -# Edit the recorded file by editing the controller-gen path -# Once you are happy with the recording, use svg-term program to generate the svg +# Stop recording with Ctrl+C when done +# Convert to SVG +svg-term --in=kb-demo.cast --out=kb-demo.svg --window --width=120 --height=30 -svg-term --in= --out demo.svg --window +# Clean up when done +kind delete cluster --name kubebuilder-demo ``` diff --git a/scripts/demo/generate-demo.sh b/scripts/demo/generate-demo.sh new file mode 100755 index 00000000000..9726e641628 --- /dev/null +++ b/scripts/demo/generate-demo.sh @@ -0,0 +1,198 @@ +#!/usr/bin/env bash + +# Copyright 2025 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)" + +# Default demo name +DEMO_NAME="${1:-kb-demo}" +DEMO_SCRIPT="${2:-${SCRIPT_ROOT}/run.sh}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +log() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +error() { + echo -e "${RED}[ERROR]${NC} $1" + exit 1 +} + +usage() { + cat << EOF +Usage: $0 [DEMO_NAME] [DEMO_SCRIPT] + +Generate an asciinema demo recording and convert it to SVG. + +Arguments: + DEMO_NAME Name of the demo (default: kb-demo) + DEMO_SCRIPT Path to the demo script to run (default: ${SCRIPT_ROOT}/run.sh) + +Examples: + $0 # Generate default kb-demo + $0 my-custom-demo # Generate custom demo with default script + $0 advanced-demo ./my-demo.sh # Generate custom demo with custom script + +EOF + exit 0 +} + +check_prerequisites() { + log "Checking prerequisites..." + + # Check for help flag + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage + fi + + # Validate demo script exists + if [[ ! -f "$DEMO_SCRIPT" ]]; then + error "Demo script not found: $DEMO_SCRIPT" + fi + + local missing_tools=() + + if ! command -v asciinema &> /dev/null; then + missing_tools+=("asciinema") + fi + + if ! command -v svg-term &> /dev/null; then + missing_tools+=("svg-term") + fi + + if ! command -v kind &> /dev/null; then + missing_tools+=("kind") + fi + + if ! command -v kubectl &> /dev/null; then + missing_tools+=("kubectl") + fi + + if [ ${#missing_tools[@]} -ne 0 ]; then + error "Missing required tools:\n$(printf ' - %s\n' "${missing_tools[@]}")" + fi + + log "All prerequisites are installed ✓" +} + +setup_cluster() { + log "Setting up Kind cluster for demo..." + "${SCRIPT_ROOT}/setup-kind.sh" + + log "Verifying cluster connection..." + kubectl cluster-info --context kind-kubebuilder-demo > /dev/null + log "Cluster connection verified ✓" +} + +record_demo() { + local recording_dir="/tmp/kb-demo-recording" + + log "Cleaning up any previous recording files..." + rm -rf "$recording_dir" + mkdir -p "$recording_dir" + + log "Starting demo recording for '${DEMO_NAME}' in 3 seconds..." + sleep 3 + + cd "$recording_dir" + asciinema rec \ + --command "$DEMO_SCRIPT" \ + --env "DEMO_AUTO_RUN=1" \ + --title "Kubebuilder Demo: ${DEMO_NAME}" \ + --idle-time-limit 2 \ + "${DEMO_NAME}.cast" +} + +convert_to_svg() { + local recording_dir="/tmp/kb-demo-recording" + local version="$1" + local svg_file="${PROJECT_ROOT}/docs/gif/${DEMO_NAME}.${version}.svg" + + log "Converting recording to SVG..." + svg-term \ + --in="${recording_dir}/${DEMO_NAME}.cast" \ + --out="$svg_file" \ + --window \ + --width=120 \ + --height=30 + + log "Demo updated! New file: docs/gif/${DEMO_NAME}.${version}.svg" + return 0 +} + +update_readme() { + local version="$1" + + # Only update README for the default kb-demo + if [[ "$DEMO_NAME" != "kb-demo" ]]; then + log "Skipping README update for custom demo '${DEMO_NAME}'" + return 0 + fi + + log "Updating README.md with new demo..." + if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + sed -i '' "s|docs/gif/kb-demo\.v[^)]*\.svg|docs/gif/kb-demo.${version}.svg|g" "${PROJECT_ROOT}/README.md" + else + # Linux + sed -i "s|docs/gif/kb-demo\.v[^)]*\.svg|docs/gif/kb-demo.${version}.svg|g" "${PROJECT_ROOT}/README.md" + fi + + log "README.md updated with new demo file ✓" +} + +cleanup() { + log "Cleaning up temporary files..." + rm -rf /tmp/kb-demo-recording + log "To clean up the demo cluster, run: make clean-demo" +} + +main() { + # Check for help flag first + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + usage + fi + + log "Starting Kubebuilder demo generation for '${DEMO_NAME}'..." + log "Using demo script: ${DEMO_SCRIPT}" + + # Extract version once to avoid duplication + local version + version=$(git -C "$PROJECT_ROOT" describe --tags --abbrev=0 2>/dev/null || echo "v4.0.0") + + check_prerequisites + setup_cluster + record_demo + convert_to_svg "$version" + update_readme "$version" + cleanup + + log "Demo generation completed successfully! 🎉" + log "Generated: docs/gif/${DEMO_NAME}.${version}.svg" +} + +main "$@" diff --git a/scripts/demo/run.sh b/scripts/demo/run.sh index bbd8980d647..b6a89bd1c21 100755 --- a/scripts/demo/run.sh +++ b/scripts/demo/run.sh @@ -13,6 +13,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Set up working directory in /tmp for clean demo +cd /tmp +rm -rf kubebuilder-demo-project +mkdir kubebuilder-demo-project +cd kubebuilder-demo-project + clear . $(dirname ${BASH_SOURCE})/util.sh diff --git a/scripts/demo/setup-kind.sh b/scripts/demo/setup-kind.sh new file mode 100755 index 00000000000..330f84fd269 --- /dev/null +++ b/scripts/demo/setup-kind.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash + +# Copyright 2025 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +CLUSTER_NAME="kubebuilder-demo" + +echo "Setting up Kind cluster for Kubebuilder demo..." + +# Check if Kind is installed +if ! command -v kind &> /dev/null; then + echo "Kind is not installed. Installing Kind..." + # Install Kind based on OS + case "$(uname -s)" in + Darwin) + if command -v brew &> /dev/null; then + brew install kind + else + echo "Please install Homebrew first or install Kind manually: https://kind.sigs.k8s.io/docs/user/quick-start/#installation" + exit 1 + fi + ;; + Linux) + # For AMD64 / x86_64 + [ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 + # For ARM64 + [ $(uname -m) = aarch64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-arm64 + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + ;; + *) + echo "Unsupported OS. Please install Kind manually: https://kind.sigs.k8s.io/docs/user/quick-start/#installation" + exit 1 + ;; + esac +fi + +# Check if kubectl is installed +if ! command -v kubectl &> /dev/null; then + echo "kubectl is not installed. Please install kubectl first." + echo "Visit: https://kubernetes.io/docs/tasks/tools/install-kubectl/" + exit 1 +fi + +# Check if cluster already exists +if kind get clusters | grep -q "^${CLUSTER_NAME}$"; then + echo "Kind cluster '${CLUSTER_NAME}' already exists." + echo "Switching kubectl context to existing cluster..." + kubectl cluster-info --context kind-${CLUSTER_NAME} +else + echo "Creating Kind cluster '${CLUSTER_NAME}'..." + + # Create Kind config for the demo + cat > /tmp/kind-config.yaml <