This document provides guidance for AI agents working with the Operator Registry project.
The Operator Registry is a Kubernetes/OpenShift component that provides operator catalog data to the Operator Lifecycle Manager (OLM). It manages operator bundles, indexes, and catalogs that enable operators to be discovered and installed in Kubernetes clusters.
opm: Main CLI tool for generating and updating registry databases and index imagesinitializer: (Deprecated) Converts operator manifests to SQLite database formatregistry-server: (Deprecated) Exposes gRPC interface to SQLite databasesconfigmap-server: Parses ConfigMaps into SQLite databases and exposes gRPC interface
pkg/client: High-level client interface for gRPC APIpkg/api: Low-level client libraries for gRPC interfacepkg/registry: Core registry types (Packages, Channels, Bundles)pkg/sqlite: (Deprecated) SQLite database interfaces for manifestspkg/lib: External interfaces and standards for operator bundlespkg/containertools: Container tooling integration
alpha/declcfg: Declarative configuration formatalpha/template: Template system for generating catalogsalpha/action: Action framework for registry operations
- Go 1.24.4: Minimum Go version required
- Cobra CLI: Command-line interface framework
- gRPC: Primary API communication protocol
- SQLite: Database backend for registry data
- OCI Images: Container image format for bundles
- Unit tests:
go test ./... - Integration tests: Located in
test/e2e/ - Linting:
make lint(uses golangci-lint) - Coverage:
make coverage
- Makefile: Primary build configuration
- GoReleaser: Release automation
- Docker: Container image builds
When adding new template types to alpha/template/:
// 1. Implement the Template interface
type MyTemplate struct {
renderBundle template.BundleRenderer
}
func (t *MyTemplate) RenderBundle(ctx context.Context, image string) (*declcfg.DeclarativeConfig, error) {
return t.renderBundle(ctx, image)
}
func (t *MyTemplate) Render(ctx context.Context, reader io.Reader) (*declcfg.DeclarativeConfig, error) {
// Implementation
}
func (t *MyTemplate) Schema() string {
return "olm.template.mytype"
}
// 2. Implement the TemplateFactory interface
type Factory struct{}
func (f *Factory) CreateTemplate(renderBundle template.BundleRenderer) template.Template {
return &MyTemplate{renderBundle: renderBundle}
}
func (f *Factory) Schema() string {
return "olm.template.mytype"
}
// 3. Register in cmd/opm/alpha/template/render.go
registry.Register(&mytype.Factory{})# Build a bundle image
podman build -t quay.io/my-namespace/my-bundle:latest -f bundle.Dockerfile .
# IMPORTANT: Bundle images must be published to a registry before they can be consumed
podman push quay.io/my-namespace/my-bundle:latest
# Add bundle to index (deprecated - use file-based catalogs instead)
opm index add --bundles quay.io/my-namespace/my-bundle:latest --from-index quay.io/my-namespace/my-index:latest --tag quay.io/my-namespace/my-index:latest
# Generate index image (deprecated - use file-based catalogs instead)
opm index add --bundles quay.io/my-namespace/my-bundle:latest --tag quay.io/my-namespace/my-index:latest- Bundle images must be published to an image registry before they can be referenced in catalogs
- FBC content requires published images -
opm renderand templates can only reference bundle images that exist in registries - Catalog images must be built and published before they can be consumed by OLM
// Load declarative config
cfg, err := declcfg.LoadFS(os.DirFS("path/to/catalog"))
// Convert to model
model, err := declcfg.ConvertToModel(cfg)
// Write declarative config
err = declcfg.Write(cfg, "output.yaml")// Create SQLite database
db, err := sqlite.Open("registry.db")
// Add bundle to database
err = db.AddBundle(bundle)
// Query packages
packages, err := db.ListPackages()The opm serve command exposes operator catalog data via a gRPC interface for consumption by OLM.
# Serve declarative configs with default settings
opm serve ./catalog-directory
# Serve with custom port and caching
opm serve ./catalog-directory --port 8080 --cache-dir /tmp/cache
# Serve with cache integrity enforcement
opm serve ./catalog-directory --cache-dir /tmp/cache --cache-enforce-integrity
# Cache-only mode (build cache without serving)
opm serve ./catalog-directory --cache-dir /tmp/cache --cache-only- Bundle images must be published to image registries before they can be referenced in FBC
- Image references must be valid -
opm servewill fail if bundle images don't exist - Catalog content is loaded at startup - changes to FBC files after startup won't be reflected
- Use
--cache-enforce-integrityto ensure cache validity before serving
The server exposes the following gRPC services:
Registry Service Methods:
ListPackages()- Stream all package namesGetPackage(name)- Get package details including channelsGetBundle(pkgName, channelName, csvName)- Get specific bundleGetBundleForChannel(pkgName, channelName)- Get latest bundle in channel (deprecated)GetChannelEntriesThatReplace(csvName)- Stream channel entries that replace a bundleGetBundleThatReplaces(csvName, pkgName, channelName)- Get bundle that replaces anotherGetChannelEntriesThatProvide(group, version, kind)- Stream entries providing an APIGetLatestChannelEntriesThatProvide(group, version, kind)- Stream latest entries providing an APIGetDefaultBundleThatProvides(group, version, kind)- Get default bundle providing an APIListBundles()- Stream all bundles
Health Service:
- Standard gRPC health check service for monitoring
Available Cache Backends:
-
PogrebV1 Backend (Default)
- Format:
pogreb.v1 - Uses embedded key-value database
- Optimized for read performance
- Stores bundles as protobuf-encoded data
- File permissions: 0770 (dirs), 0660 (files)
- Format:
-
JSON Backend
- Format:
json - Human-readable JSON files
- Easier debugging and inspection
- Stores bundles as JSON files
- File permissions: 0750 (dirs), 0640 (files)
- Format:
Cache Configuration:
// Cache options
type CacheOptions struct {
Log *logrus.Entry
Format string // "pogreb.v1" or "json"
}
// Create cache with specific backend
cache, err := cache.New("/cache/dir",
cache.WithLog(logger),
cache.WithFormat("pogreb.v1"))Cache Integrity:
- Automatic digest computation for cache validation
- Integrity checks compare source content with cached data
- Cache rebuilds when integrity check fails
--cache-enforce-integrityflag ensures cache is valid before serving
Performance Considerations:
- PogrebV1: Better for production (faster reads, smaller footprint)
- JSON: Better for development (human-readable, easier debugging)
- Cache directory should be persistent for production deployments
- Use
--cache-onlyfor pre-building cache in CI/CD pipelines
opm registry serve- (Deprecated) Serve SQLite database via gRPCopm registry add- (Deprecated) Add bundles to SQLite databaseopm registry rm- (Deprecated) Remove packages from SQLite databaseopm registry prune- (Deprecated) Prune SQLite databaseopm registry prune-stranded- (Deprecated) Prune stranded bundles from SQLite databaseopm registry deprecatetruncate- (Deprecated) Deprecate bundles in SQLite databaseopm registry mirror- (Deprecated) Mirror SQLite-based catalogs
opm index add- (Deprecated) Add bundles to SQLite-based indexopm index rm- (Deprecated) Delete operators from SQLite-based indexopm index export- (Deprecated) Export SQLite-based indexopm index prune- (Deprecated) Prune SQLite-based indexopm index prune-stranded- (Deprecated) Prune stranded bundles from SQLite-based indexopm index deprecatetruncate- (Deprecated) Deprecate bundles in SQLite-based index
SQLQuerier- (Deprecated) Query interface for SQLite databasesSQLLoader- (Deprecated) Load bundles into SQLite databasesDeprecationAwareLoader- (Deprecated) Handle bundle deprecations in SQLiteSQLDeprecator- (Deprecated) Deprecate bundles in SQLite databases
RegistryUpdater- (Deprecated) Update SQLite-based registriesRegistryDeleter- (Deprecated) Delete from SQLite-based registriesRegistryDeprecator- (Deprecated) Deprecate bundles in SQLite-based registries
From SQLite to File-Based Catalogs:
-
Replace
opm registry serve→ Useopm serve# Old (deprecated) opm registry serve --database bundles.db # New (recommended) opm serve ./catalog-directory
-
Replace
opm index add→ Useopm alpha generate dockerfile+opm serve# Old (deprecated) opm index add --bundles quay.io/my/bundle:latest --tag quay.io/my/index:latest # New (recommended) opm alpha generate dockerfile ./catalog-directory # Build and serve the generated Dockerfile
-
Replace SQLite database operations → Use declarative config files
# Old (deprecated) - SQLite database manipulation opm registry add --database bundles.db --bundles quay.io/my/bundle:latest # New (recommended) - File-based catalog # Create catalog files directly in ./catalog-directory/
-
Convert existing SQLite catalogs → Use migration tools
# Convert SQLite index image to FBC opm migrate quay.io/my-namespace/my-index:latest ./fbc-output --output yaml # Convert SQLite database to FBC opm render ./bundles.db --output yaml > catalog.yaml # Convert FBC to a basic catalog template for simpler maintenance opm alpha render-template basic ./catalog.yaml
When using deprecated commands, you will see warnings like:
DEPRECATION NOTICE:
Sqlite-based catalogs and their related subcommands are deprecated. Support for
them will be removed in a future release. Please migrate your catalog workflows
to the new file-based catalog format.
Action Required: Plan your migration to file-based catalogs to avoid future compatibility issues.
The opm migrate command converts SQLite-based index images or database files to file-based catalogs:
# Migrate from SQLite index image to FBC
opm migrate quay.io/my-namespace/my-index:latest ./fbc-output --output yaml
# Migrate from SQLite database file to FBC
opm migrate ./bundles.db ./fbc-output --output json
# Migrate with specific migration level
opm migrate quay.io/my-namespace/my-index:latest ./fbc-outputThe opm render command can convert various sources to FBC format:
# Render from SQLite database to FBC
opm render ./bundles.db --output yaml > catalog.yaml
# Render from bundle images to FBC
opm render quay.io/my/bundle:v1.0.0 quay.io/my/bundle:v1.1.0 --output json
# Render with image reference template for missing bundle references
opm render ./bundle-directory --alpha-image-ref-template "quay.io/my-registry/{{.Package}}:{{.Version}}" --output yamlTemplates can generate FBC content from structured input files:
# Generate FBC from basic template
opm alpha render-template basic ./my-template.yaml --output yaml
# Generate FBC from semver template
opm alpha render-template semver ./semver-template.yaml --output json
# Auto-detect template type from schema field
opm alpha render-template ./template-file.yaml --output yamlFor complex migrations, combine multiple tools:
# Step 1: Migrate SQLite to FBC
opm migrate quay.io/my-namespace/my-index:latest ./fbc-output --output yaml
# Step 2: Convert to basic template format (if needed)
opm alpha render-template basic ./fbc-output/package.yaml --output yaml > template.yaml
# Step 3: Modify template as needed, then render final FBC
opm alpha render-template basic ./template.yaml --output yaml > final-catalog.yaml
# Step 4: Serve the new FBC catalog
opm serve ./final-catalog.yaml- Bundle images must exist in registries before they can be referenced in FBC
- Image references are required - use
--alpha-image-ref-templateif bundle images don't exist yet - Migration levels control which schema transformations are applied
- Output formats include JSON (streamable) and YAML (human-readable)
- Templates provide flexibility for custom catalog generation workflows
cmd/: CLI applications and main functionspkg/: Reusable Go packagesalpha/: Experimental features (may change)test/: Test files and test datadocs/: Documentationmanifests/: Example operator manifestsbundles/: Test bundle data
go.mod: Go module dependenciesMakefile: Build and test commandsREADME.md: Project overview and usageOWNERS: Code ownership and review requirements
if err != nil {
return fmt.Errorf("context: %w", err)
}func (r *Renderer) Run(ctx context.Context) error {
// Always pass context to long-running operations
return r.processBundles(ctx)
}import "github.com/sirupsen/logrus"
logrus.Info("Processing bundle", "image", image)
logrus.Debug("Bundle details", "bundle", bundle)func TestMyFunction(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{"valid input", "test", "expected"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := MyFunction(tt.input)
require.Equal(t, tt.expected, result)
})
}
}- Use
test/e2e/directory - Test with real bundle images
- Verify end-to-end workflows
- Bundle validation errors: Check bundle format and annotations
- Image pull failures: Verify image references and registry access
- Database corruption: Rebuild database from source bundles
- Template rendering errors: Check template syntax and schema
- Cache integrity failures: Rebuild cache or disable integrity checks
- gRPC connection issues: Verify port availability and firewall settings
- Memory issues with large catalogs: Use persistent cache directory
- Slow startup times: Pre-build cache with
--cache-onlyflag - SQLite deprecation warnings: Migrate to file-based catalogs using
opm serve - Hidden commands: Some deprecated commands are hidden but still accessible
# Validate bundle
opm alpha bundle validate ./bundle
# Inspect index
opm index export --from-index quay.io/my-namespace/my-index:latest
# Debug template rendering
opm alpha render-template --help
# Serve with debug logging
opm serve ./catalog --debug
# Serve with profiling enabled
opm serve ./catalog --pprof-addr localhost:6060 --pprof-capture-profiles
# Test gRPC connectivity
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext localhost:50051 api.Registry/ListPackages
# Deprecated SQLite commands (avoid using these)
opm registry serve --database bundles.db # Use 'opm serve' instead
opm index add --bundles quay.io/my/bundle:latest --tag quay.io/my/index:latest # Use file-based catalogs- Follow Go standard formatting (
gofmt) - Use
golangci-lintfor additional checks - Write comprehensive tests
- Document public APIs
- Use conventional commit format
- Include context and reasoning
- Reference issues when applicable
- Ensure all tests pass
- Run
make lintand fix issues - Update documentation if needed
- Request review from OWNERS
- Always verify bundle image signatures
- Use trusted registries
- Scan images for vulnerabilities
- Validate all input data
- Sanitize user-provided content
- Use secure defaults
- Use TLS for gRPC connections
- Implement proper authentication
- Validate network policies
- Use appropriate indexes
- Batch operations when possible
- Monitor query performance
- Use streaming for large datasets
- Implement proper cleanup
- Monitor memory usage
- Cache frequently accessed data
- Implement cache invalidation
- Use appropriate cache sizes
This document should be updated as the project evolves. For specific implementation details, refer to the source code and inline documentation.