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 rendering and serving file-based catalogs
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/lib: External interfaces and standards for operator bundlespkg/containertools: Container tooling integrationpkg/cache: Caching backends for file-based catalogs
alpha/declcfg: Declarative configuration formatalpha/template: Template system for generating catalogsalpha/action: Action framework for registry operations
- Go 1.26.3: Minimum Go version required
- Cobra CLI: Command-line interface framework
- gRPC: Primary API communication protocol
- Declarative Config (FBC): File-based catalog format 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
# Render bundle to declarative config
opm render quay.io/my-namespace/my-bundle:latest --output yaml > catalog.yaml
# Generate catalog from multiple bundles
opm render quay.io/my-namespace/my-bundle:v1.0.0 quay.io/my-namespace/my-bundle:v1.1.0 --output yaml- 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(context.TODO(), os.DirFS("path/to/catalog"))
// Convert to model
model, err := declcfg.ConvertToModel(*cfg)
// Write declarative config as YAML
f, err := os.Create("output.yaml")
err = declcfg.WriteYAML(*cfg, f)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, opm index) have been removed from this project. All catalog workflows now use the file-based catalog (FBC) format exclusively.
Migration: For older versions that supported SQLite-to-FBC migration, refer to previous releases or documentation versions.
The opm render command converts various sources to FBC format:
# 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 yamlcmd/: 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
- 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
# Validate bundle
opm alpha bundle validate ./bundle
# 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- 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.