Skip to content

About

Core library for building Codesphere managed service provider backends. Implement the provider interface and the library serves it over the Codesphere REST contract.

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

managed-services-lib

License CI Security

Core library for building Codesphere managed-service provider backends. Implement one interface; the library serves it over the Codesphere REST contract.

Not a runnable service. Start from managed-services-template for a working server with an example provider, Dockerfile, and CI.

Install

go get github.com/codesphere-cloud/managed-services-lib

Go 1.26+.

Provider interface

type Provider[PlanParams, Config, Secrets, Details, UpdateParams any] interface {
	Create(ctx context.Context, req CreateRequest[PlanParams, Config, Secrets]) error
	List(ctx context.Context) ([]model.ServiceID, error)
	GetStatus(ctx context.Context, ids []model.ServiceID) (map[model.ServiceID]ServiceStatus[PlanParams, Config, Details], error)
	Update(ctx context.Context, req UpdateRequest[UpdateParams]) error
	Delete(ctx context.Context, id model.ServiceID) error
}
type CreateRequest[PlanParams, Config, Secrets any] struct {
	ID              model.ServiceID
	TeamID          int
	CustomSubdomain *string
	Plan            PlanParams // contents of plan.parameters
	Config          Config
	Secrets         Secrets
	RecoverFrom     *model.RecoverFrom // set when restoring into a new service
}

type UpdateRequest[UpdateParams any] struct {
	ID              model.ServiceID
	TeamID          int
	CustomSubdomain *string
	Pause           *bool       // nil = leave as is
	Params          UpdateParams // your partial PATCH payload
}

The split between the contract and your provider is visible in the signatures — you never declare the contract's own fields or envelopes yourself:

The contract defines You define
id, teamId, customSubdomain — fields on the request struct PlanParams — contents of plan.parameters
pause on update, and pause in the status response Config — contents of config
the plan: {parameters: …} wrapper, unwrapped on the way in and re-wrapped on the way out Secrets — contents of secrets
msId and retentionDays on backup requests Details — read-only status data (hostnames, ports, readiness)
the {plan, config, details, pause} status envelope (ServiceStatus) UpdateParams — your partial PATCH payload
HTTP status codes and error mapping

PATCH bodies are partial, so make UpdateParams fields pointers to tell "not sent" from "sent empty".

Build status values with provider.NewServiceStatus(plan, config, details, pause, error)

Embed provider.Base for the shared dependencies (Kubernetes client, logger) and helpers.

Backups are an opt-in capability:

type Backups interface {
	TakeBackup(ctx context.Context, req BackupRequest) error
	GetBackupStatus(ctx context.Context, req BackupRequest) (model.BackupStatus, error)
	DeleteBackup(ctx context.Context, req BackupRequest) error
}

BackupRequest carries BackupID, ServiceID (the msId field), TeamID, the backup store's Config (model.BackupStoreConfig) and Secrets (model.BackupStoreSecrets), and RetentionDays. The same store arrives in CreateRequest.RecoverFrom, which names either a backup ID or, for point-in-time recovery, a source MsID and Time. Both are validated against their binding tags before your provider is called. A provider that supports backups implements Backups and calls RegisterBackupRoutes.

Wiring

cfg, _ := config.Load()
k8s, _ := client.NewKubernetesClient(cfg.Kubeconfig)
logger := slog.Default()

routes := map[string]func(*gin.RouterGroup){
	"mysvc": func(g *gin.RouterGroup) {
		p := mysvc.NewProvider(k8s, logger)
		provider.RegisterRoutes(g, p)       // CRUD
		provider.RegisterBackupRoutes(g, p) // backups
	},
}

server, _ := api.NewServer(cfg, routes)
server.Run()

RegisterRoutes mounts the CRUD endpoints under /api/v1/{name}; RegisterBackupRoutes adds the /backups endpoints for providers that implement Backups.

Detached Jobs

Some operations (backups, restores, migrations) are easier to run as one-shot Kubernetes Jobs, detached from the provider pod.

  • client.JobRunner (also on provider.Base as Jobs) — Run / State / Delete / Replace a one-shot Job, with an optional owned credentials Secret injected via secretKeyRef.
  • provider.ServiceJob / ServiceJobSpec — build a JobSpec with a consistent name (<operation>-<key>) and identity labels; BackupStatusFromJob / OperationStatusFromJob map a Job's state to a status.
spec := provider.ServiceJobSpec(provider.ServiceJob{
	Operation: provider.JobOpBackup, MsID: id, Key: backupID,
	Image: img, Command: []string{"/backup"},
	Env: env, Secrets: secrets, // whatever your image reads
	ImagePullSecrets: []string{"regcred"}, // for a private registry
})
err := p.Jobs.Run(ctx, ns, spec)

See the package docs and provider/servicejob_usage_test.go for details.

Telemetry

Call telemetry.Setup once at startup and its shutdown func on exit:

shutdown, err := telemetry.Setup(ctx, "ms-backend-mysvc")
defer shutdown(context.Background())

It exports over OTLP to OTEL_EXPORTER_OTLP_ENDPOINT and does nothing when that is unset. Instrumented out of the box: incoming requests (http.server.*, except /health and /ready), Kubernetes API calls (http.client.*) and Go runtime metrics, as metrics and traces. Add your own metrics with otel.Meter(...), and wrap other HTTP clients with telemetry.Transport.

Logs stay JSON on stdout. Wrap your handler with telemetry.LogHandler so lines logged with a request context (InfoContext etc., and the server's own request log) get trace_id and span_id:

slog.SetDefault(slog.New(telemetry.LogHandler(slog.NewJSONHandler(os.Stdout, nil))))

Configuration

config.Load() reads these environment variables:

Variable Default
PORT 8080 HTTP port
API_KEY — auth key (off if unset)
KUBECONFIG — kubeconfig path (in-cluster if unset)
ENVIRONMENT development development / production

This is framework config only. Provider-specific config (storage class, credentials, image versions) belongs in your provider's constructor.

Development

make test, make lint, make mocks. make all runs everything.

About

Core library for building Codesphere managed service provider backends. Implement the provider interface and the library serves it over the Codesphere REST contract.

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages