Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Binaries for programs and plugins
bin/
dist/

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool
*.out
coverage.html
coverage.txt

# IDE and Editor files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
*.iml

# Temporary files
*.tmp
*.log

# Kubernetes generated files
*.kubeconfig
kubeconfig

# OS specific
.DS_Store
Thumbs.db

# Local development
.env
.env.local
*.local
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Tool Versions
CONTROLLER_TOOLS_VERSION ?= v0.18.0

## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object paths="./..."

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd:allowDangerousTypes=true webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten.
$(CONTROLLER_GEN): $(LOCALBIN)
test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)
114 changes: 114 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,115 @@
# OpenEverest Provider SDK
A Go SDK for building database providers for the Everest platform. This SDK simplifies the creation of Kubernetes controllers that manage database lifecycle through the `DataStore` custom resource.

## 🎯 Purpose of this PoC

This repository contains a **proof-of-concept** implementation of the Provider SDK. The primary goals are:

1. **Evaluate SDK usability** - Ensure the SDK is easy to use for provider developers
2. **Validate design decisions** - Test the proposed architecture with a real implementation
3. **Gather team feedback** - Enable the team to review and help improve the SDK

## 📚 Documentation Guide

| Document | Audience | Description |
|----------|----------|-------------|
| [SDK Overview](docs/SDK_OVERVIEW.md) | All reviewers | Understand the problem and SDK architecture |
| [Provider CR Generation](docs/PROVIDER_CR_GENERATION.md) | Developers | How to generate the Provider CR manifest |
| [Examples Guide](examples/README.md) | Developers | Walk through the PSMDB reference implementation |
| [Metadata Helpers](docs/METADATA_HELPERS.md) | Developers | Working with provider metadata |

## 🚀 Quick Start

### Prerequisites

- Go 1.21+
- Access to a Kubernetes cluster (or use `kind`)
- `kubectl` configured

### Run the PSMDB Example

```bash
# Clone the repository
git clone https://github.com/openeverest/provider-sdk.git
cd provider-sdk

# Install SDK CRDs (in production: auto-installed with Everest)
kubectl apply -f config/crd/bases/

# Install PSMDB operator (in production: packaged in provider Helm chart)
kubectl apply --server-side -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v1.21.1/deploy/bundle.yaml

# Run the provider
cd examples/psmdb
go run cmd/provider/main.go
```

### Create a Test DataStore

```bash
kubectl apply -f examples/datastore-simple.yaml
```

## 📁 Repository Structure

```
provider-sdk/
├── README.md # This file
├── docs/
│ ├── SDK_OVERVIEW.md # SDK architecture and concepts
│ ├── METADATA_HELPERS.md # Working with metadata
│ └── PROVIDER_CR_GENERATION.md # How to generate Provider manifests
├── pkg/
│ ├── apis/v2alpha1/ # CRD types (DataStore, Provider)
│ ├── controller/ # SDK core (Context handle, Status, etc.)
│ ├── reconciler/ # Reconciler implementations
│ └── server/ # HTTP server for schemas
├── examples/
│ └── psmdb/ # PSMDB provider example
│ ├── cmd/
│ │ └── provider/ # Provider entrypoint
│ ├── internal/ # PSMDB business logic
│ └── psmdbspec/ # PSMDB types and schemas
└── config/crd/bases/ # CRD manifests
```

## 🔍 How to Review This PoC

### For Decision Makers

1. **Read the [SDK Overview](docs/SDK_OVERVIEW.md)** to understand the problem and approach
2. **Review the decision documents** in `docs/decisions/`
3. **Look at the [examples](examples/)** to see both approaches in action

### For Developers

1. **Start with [examples/README.md](examples/README.md)** for a hands-on walkthrough
2. **Examine the SDK code** in `pkg/controller/` - especially:
- [common.go](pkg/controller/common.go) - The `Context` handle abstraction
- [interface.go](pkg/controller/interface.go) - Provider interface types
3. **Run the examples** and create test DataStore resources

### Questions to Consider

When reviewing, please consider:

1. **Usability**: Is the SDK easy to understand and use?
2. **API Design**: Is the interface design intuitive and idiomatic?
3. **Missing Features**: What's missing that would be needed for production?
4. **Naming**: Are the names (Context, Status, etc.) clear and appropriate?

## 📝 Providing Feedback

Please provide feedback through:
- GitHub Issues for specific problems or suggestions
- PR comments for code-level feedback
- Team discussions for design decisions

## 🔗 Related Links

- [Everest Platform](https://github.com/percona/everest) - Main Everest repository
- [PSMDB Operator](https://github.com/percona/percona-server-mongodb-operator) - Percona MongoDB operator

---

**Status**: Proof of Concept | **Version**: 0.1.0
125 changes: 125 additions & 0 deletions cmd/provider-sdk/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package main

// Provider SDK CLI Tool
//
// This tool provides utilities for provider developers, including:
// - generate-manifest: Generate a Provider CR YAML from Go code
//
// Usage:
// provider-sdk generate-manifest --name <provider-name> --namespace <namespace> --output <file>
//
// See docs/PROVIDER_CR_GENERATION.md for detailed documentation.

import (
"flag"
"fmt"
"os"
)

func main() {
if len(os.Args) < 2 {
printUsage()
os.Exit(1)
}

switch os.Args[1] {
case "generate-manifest":
generateManifestCmd(os.Args[2:])
case "help", "-h", "--help":
printUsage()
default:
fmt.Fprintf(os.Stderr, "Unknown command: %s\n", os.Args[1])
printUsage()
os.Exit(1)
}
}

func printUsage() {
fmt.Println(`Provider SDK CLI Tool

Usage:
provider-sdk <command> [options]

Commands:
generate-manifest Generate a Provider CR YAML manifest from Go code
help Show this help message

Use "provider-sdk <command> -h" for more information about a command.`)
}

func generateManifestCmd(args []string) {
fs := flag.NewFlagSet("generate-manifest", flag.ExitOnError)
name := fs.String("name", "", "Provider name (required)")
namespace := fs.String("namespace", "", "Namespace for the Provider CR (optional, omit for cluster-scoped)")
output := fs.String("output", "", "Output file path (default: stdout)")

fs.Usage = func() {
fmt.Println(`Generate a Provider CR YAML manifest from Go code.

This command is intended to be called from a Go generate directive in your
provider's main package. It reads the provider metadata from your Go code
and generates a YAML manifest that can be included in your Helm chart.

Usage:
provider-sdk generate-manifest [options]

Options:`)
fs.PrintDefaults()
fmt.Println(`
Example usage in your provider code:

//go:generate provider-sdk generate-manifest --name percona-server-mongodb-operator --output ../../charts/provider/templates/provider.yaml

The actual metadata is read from your provider implementation via a special
init mechanism. See the PSMDB example for details.

See docs/PROVIDER_CR_GENERATION.md for complete workflow documentation.`)
}

if err := fs.Parse(args); err != nil {
os.Exit(1)
}

if *name == "" {
fmt.Fprintln(os.Stderr, "Error: --name is required")
fs.Usage()
os.Exit(1)
}

// Note: In a real implementation, this would load the provider metadata
// from a compiled Go binary or through a plugin mechanism.
// For now, we provide a library function that providers call directly.
fmt.Fprintf(os.Stderr, `Note: This CLI is a placeholder for the generate-manifest workflow.

In practice, provider developers should use the library function directly:

// In your provider's gen.go file:
package main

import (
"os"
sdk "github.com/openeverest/provider-sdk/pkg/controller"
)

func main() {
metadata := defineMetadata() // Your metadata definition
yaml, err := metadata.ToYAML("%s", "%s")
if err != nil {
panic(err)
}

// Write to file or stdout
if err := os.WriteFile("provider.yaml", []byte(yaml), 0644); err != nil {
panic(err)
}
}

See examples/psmdb_interface.go for a complete example.
`, *name, *namespace)

// For demonstration, we'll generate a template
if *output != "" {
fmt.Fprintf(os.Stderr, "Would write to: %s\n", *output)
}
}

Loading