Multitenancy
The pkg/multitenant package provides an in-memory tenant-to-client registry for the Aruba Cloud SDK. It is useful when your application serves multiple tenants and each tenant needs its own aruba.Client.
Overview
The package exposes:
- A
Multitenantinterface to create, store, retrieve, and clean up tenant clients - A default implementation backed by a map and mutex
- A cleanup routine helper to periodically remove stale tenants
Core files:
pkg/multitenant/multitenant.gopkg/multitenant/cleanup_routine.go
Main Interface
The Multitenant interface supports these operations:
New(tenant string) error: create client using template optionsNewFromOptions(tenant string, options *aruba.Options) error: create client from explicit optionsAdd(tenant string, client aruba.Client): inject an existing clientGet(tenant string) (aruba.Client, bool): retrieve client with existence flagMustGet(tenant string) aruba.Client: retrieve or terminate process if missingGetOrNil(tenant string) aruba.Client: retrieve or returnnilCleanUp(from time.Duration): delete inactive tenants
Creating a Manager
Empty manager
Use this when you want to add tenant clients manually or via NewFromOptions:
mt := multitenant.New()
Manager with template
Use this when tenants share a common base configuration:
opts := aruba.DefaultOptions(clientID, clientSecret)
mt := multitenant.NewWithTemplate(opts)
// Later:
if err := mt.New("tenant-a"); err != nil {
// handle error
}
Usage Patterns
Add an existing client
client, err := aruba.NewClient(aruba.DefaultOptions(clientID, clientSecret))
if err != nil {
// handle error
}
mt.Add("tenant-a", client)
Create from tenant-specific options
tenantOpts := aruba.DefaultOptions(tenantClientID, tenantClientSecret)
if err := mt.NewFromOptions("tenant-a", tenantOpts); err != nil {
// handle error
}
Retrieve a client
client, ok := mt.Get("tenant-a")
if !ok {
// tenant not found
}
If you require strict existence:
client := mt.MustGet("tenant-a")
Automatic Cleanup Routine
The package also includes StartCleanupRoutine in cleanup_routine.go. It runs CleanUp periodically in a background goroutine.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stopCleanup := multitenant.StartCleanupRoutine(
ctx,
mt,
5*time.Minute, // tick interval
24*time.Hour, // remove tenants inactive for 24h
)
defer stopCleanup()
Defaults:
tickInterval: 1 hour if zero/negativefromDuration: 24 hours if zero/negative
Notes
- This implementation is in-memory and process-local.
- Tenant lifecycle is based on
lastUsage. CleanUpremoves stale and invalid entries (nilentry/client).
Example Usage (examples/all-resources/orchestrator_multitenancy.go)
For a complete example see:
examples/all-resources/orchestrator_multitenancy.go
Key snippet (cache + per-tenant Vault credentials):
c, ok := r.multiTenantClient.Get(tenant)
if ok {
return c, nil
}
options := aruba.NewOptions().
WithBaseURL(r.config.APIGateway).
WithDefaultTokenIssuerURL().
WithVaultCredentialsRepository(
r.config.VaultAddress,
r.config.KVMount,
tenant, // tenant -> kvPath (e.g. ARU-297647)
r.config.Namespace,
r.config.RolePath,
r.config.RoleID,
r.config.RoleSecret,
)
client, err := aruba.NewClient(options)
if err != nil {
return nil, err
}
r.multiTenantClient.Add(tenant, client)
return client, nil