Documentation
¶
Overview ¶
Package config provides configuration loading and validation for the nstance-server.
Index ¶
- func DeleteGroup(ctx context.Context, loader *Loader, tenant, key string) error
- func GetGroups(ctx context.Context, loader *Loader, tenant string) (map[string]GroupConfig, error)
- func HashInfraConfig(cfg MergedConfig) string
- func HashRuntimeConfig(cfg MergedConfig) string
- func IntPtr(i int) *int
- func RegisterCustomValidators(v *validator.Validate) error
- func UpsertGroup(ctx context.Context, loader *Loader, tenant, key string, group GroupConfig) error
- type AdvertiseConfig
- type BindConfig
- type CertConfig
- type ClusterConfig
- type ClusterStorageConfig
- type Config
- func (c *Config) Clone() (*Config, error)
- func (c *Config) GetMergedConfig(template string, groupConfig GroupConfig) (*MergedConfig, error)
- func (c *Config) GetShardStoragePrefix() string
- func (c *Config) IsClusterLeaderElectionEnabled() bool
- func (c *Config) IsShardLeaderElectionEnabled() bool
- func (c *Config) ResolveSubnetKey(key string) ([]string, error)
- func (c *Config) SetDefaults()
- func (c *Config) Validate() error
- func (c *Config) ValidateDynamicSubnetKey(key string) error
- func (c *Config) ValidateSubnetConfig() error
- type ConfigMetadata
- type DefaultsConfig
- type Duration
- type EncryptionKeyConfig
- type ErrorExitJitterConfig
- type ExpiryConfig
- type FileConfig
- type GarbageCollectionConfig
- type GroupConfig
- type ImageConfig
- type ImageFilter
- type InfraConfig
- type InstanceConfig
- type KeyConfig
- type LeaderElectionConfig
- type LeaderNetworkConfig
- type LoadBalancerConfig
- type Loader
- func (l *Loader) CleanCache(ctx context.Context) error
- func (l *Loader) DeleteDynamicGroup(ctx context.Context, tenant, key string) error
- func (l *Loader) GetCurrent() *Config
- func (l *Loader) GetDynamicGroup(tenant, key string) (GroupConfig, bool)
- func (l *Loader) GetMetadata() *ConfigMetadata
- func (l *Loader) LoadConfigAndGroups(ctx context.Context, forceRefresh bool) (*Config, error)
- func (l *Loader) LoadDynamicGroups(ctx context.Context) (map[string]map[string]GroupConfig, error)
- func (l *Loader) RefreshGroups(ctx context.Context) error
- func (l *Loader) SetConfig(config *Config)
- func (l *Loader) SetDynamicGroup(ctx context.Context, tenant, key string, group GroupConfig) error
- func (l *Loader) SyncGroupsToCache(ctx context.Context) error
- type LoaderOptions
- type MergedConfig
- type SecretsConfig
- type ShardConfig
- type TemplateConfig
- type TenantGroup
- type UserdataConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DeleteGroup ¶
DeleteGroup removes a dynamic group for a specific tenant. If group exists in static config, only the dynamic overrides are removed.
func GetGroups ¶
GetGroups returns all groups for a tenant, merging static and dynamic configs. Returns a map of final merged group configurations (map key is the group key).
func HashInfraConfig ¶
func HashInfraConfig(cfg MergedConfig) string
HashInfraConfig computes the infra config hash from merged config This covers immutable fields requiring VM replacement
func HashRuntimeConfig ¶
func HashRuntimeConfig(cfg MergedConfig) string
HashRuntimeConfig computes the runtime config hash from merged config This covers vars and files (anything that can be pushed to existing instances)
func RegisterCustomValidators ¶
RegisterCustomValidators registers custom validation functions
func UpsertGroup ¶
UpsertGroup creates or updates a group for a specific tenant. - If group exists in static config: validates only size/instanceType/vars are changed - If group exists in dynamic config: merges non-zero fields - If new group: validates all required fields are present, writes to dynamic config
Types ¶
type AdvertiseConfig ¶
type AdvertiseConfig struct {
HealthAddr string `json:"health_addr" validate:"required,addr"`
ElectionAddr string `json:"election_addr" validate:"required,addr"`
RegistrationAddr string `json:"registration_addr" validate:"required,addr"`
OperatorAddr string `json:"operator_addr" validate:"required,addr"`
AgentAddr string `json:"agent_addr" validate:"required,addr"`
}
AdvertiseConfig defines server advertised addresses with per-service addresses
type BindConfig ¶
type BindConfig struct {
HealthAddr string `json:"health_addr" validate:"required,addr"`
ElectionAddr string `json:"election_addr" validate:"required,addr"`
RegistrationAddr string `json:"registration_addr" validate:"required,addr"`
OperatorAddr string `json:"operator_addr" validate:"required,addr"`
AgentAddr string `json:"agent_addr" validate:"required,addr"`
}
BindConfig defines server binding configuration with per-service addresses
type CertConfig ¶
type CertConfig struct {
Kind string `json:"kind" validate:"required,oneof=client server"`
CN *string `json:"cn"` // Common Name (supports templating)
Organization []string `json:"organization"` // Organization (for client certs)
DNS []string `json:"dns"` // DNS SANs (supports templating)
IP []string `json:"ip"` // IP SANs (supports templating)
Country []string `json:"country"` // Country (C)
Province []string `json:"province"` // State/Province (ST)
Locality []string `json:"locality"` // Locality (L)
Street []string `json:"street"` // Street Address
PostalCode []string `json:"postal_code"` // Postal Code
TTL int `json:"ttl"` // Certificate TTL in hours (default: 8760 = 1 year)
}
CertConfig defines certificate template configuration
type ClusterConfig ¶
type ClusterConfig struct {
ID string `json:"id" validate:"required"`
Storage *ClusterStorageConfig `json:"storage,omitempty"`
Secrets SecretsConfig `json:"secrets" validate:"required"`
LeaderElection LeaderElectionConfig `json:"leader_election"`
}
ClusterConfig defines cluster-scoped configuration shared across all shards.
type ClusterStorageConfig ¶
type ClusterStorageConfig struct {
Provider string `json:"provider" validate:"required,oneof=s3 gcs file"`
Bucket string `json:"bucket"`
Region string `json:"region,omitempty"`
Endpoint string `json:"endpoint,omitempty"` // Used for S3-compatible object stores (SeaweedFS, MinIO, Ceph RGW)
Prefix string `json:"prefix"` // Default: "cluster/"
}
ClusterStorageConfig defines optional separate storage for cluster-scoped data. If not specified, the shard bucket is used with the "cluster/" prefix.
type Config ¶
type Config struct {
Cluster ClusterConfig `json:"cluster" validate:"required"`
Shard ShardConfig `json:"shard" validate:"required"`
LoadBalancers map[string]LoadBalancerConfig `json:"load_balancers"`
Images map[string]ImageConfig `json:"images"`
Certificates map[string]CertConfig `json:"certificates"`
Defaults DefaultsConfig `json:"defaults"`
Templates map[string]TemplateConfig `json:"templates" validate:"required"`
Groups map[string]map[string]GroupConfig `json:"groups"` // tenant -> group key -> config
}
Config represents the complete Nstance Server configuration
func ParseBytes ¶
ParseBytes parses and validates configuration from bytes
func ValidateFile ¶
ValidateFile validates a local configuration file
func (*Config) GetMergedConfig ¶
func (c *Config) GetMergedConfig(template string, groupConfig GroupConfig) (*MergedConfig, error)
GetMergedConfig resolves and merges configuration for a specific template/group combination
func (*Config) GetShardStoragePrefix ¶
GetShardStoragePrefix returns the shard storage prefix in the format "shard/{shard.id}/".
func (*Config) IsClusterLeaderElectionEnabled ¶
IsClusterLeaderElectionEnabled returns true if cluster leader election is enabled or not set.
func (*Config) IsShardLeaderElectionEnabled ¶
IsShardLeaderElectionEnabled returns true if shard leader election is enabled or not set.
func (*Config) ResolveSubnetKey ¶
ResolveSubnetKey resolves a subnet pool ID to its provider subnet IDs.
func (*Config) SetDefaults ¶
func (c *Config) SetDefaults()
SetDefaults sets default values for optional fields
func (*Config) ValidateDynamicSubnetKey ¶
ValidateDynamicSubnetKey validates that the given subnet pool ID is allowed for external requests (dynamic groups, per-instance overrides). Returns nil if allowed, error otherwise.
func (*Config) ValidateSubnetConfig ¶
ValidateSubnetConfig validates the subnet configuration at config load time. Returns an error if validation fails.
type ConfigMetadata ¶
type ConfigMetadata struct {
ETag string `json:"etag"`
LastModified time.Time `json:"last_modified"`
Size int64 `json:"size"`
}
ConfigMetadata contains metadata about a configuration file
type DefaultsConfig ¶
type DefaultsConfig struct {
Args map[string]interface{} `json:"args"`
Vars map[string]string `json:"vars"`
Userdata *UserdataConfig `json:"userdata,omitempty"`
}
DefaultsConfig defines global defaults
type Duration ¶
Duration is a wrapper around time.Duration that supports parsing duration strings in JSON
func (Duration) MarshalJSON ¶
func (*Duration) UnmarshalJSON ¶
type EncryptionKeyConfig ¶
type EncryptionKeyConfig struct {
Provider string `json:"provider" validate:"required,oneof=env file aws-secrets-manager gcp-secret-manager"`
Options map[string]interface{} `json:"options,omitempty"` // Provider-specific options
Source string `json:"source" validate:"required"` // env var name, file path, secret name, or AWS secret ARN
}
EncryptionKeyConfig defines Encryption Key configuration
type ErrorExitJitterConfig ¶
type ErrorExitJitterConfig struct {
MinDelay Duration `json:"min_delay"` // Minimum delay before exit (default: 10s)
MaxDelay Duration `json:"max_delay"` // Maximum delay before exit (default: 40s)
}
ErrorExitJitterConfig defines jittered delay timing before server exits on error
type ExpiryConfig ¶
type ExpiryConfig struct {
EligibleAge Duration `json:"eligible_age,omitempty"` // Age at which managed instances become eligible for opportunistic expiry
ForcedAge Duration `json:"forced_age,omitempty"` // Age at which managed instances are expired immediately
OndemandAge Duration `json:"ondemand_age,omitempty"` // Maximum age for on-demand instances before forced expiry
}
ExpiryConfig defines instance expiry configuration
type FileConfig ¶
type FileConfig struct {
Kind string `json:"kind" validate:"required,oneof=secret certificate env json string"`
Source string `json:"source,omitempty"` // For secrets: secret name
Template interface{} `json:"template,omitempty"` // For certificates: string template name; for env/json/string: template content
Key *KeyConfig `json:"key,omitempty"` // For certificates: key reference
}
FileConfig defines file configuration (secrets, certificates, or templates)
type GarbageCollectionConfig ¶
type GarbageCollectionConfig struct {
Interval Duration `json:"interval,omitempty"` // How often to run GC (e.g., "2m"); 0 disables GC
RegistrationTimeout Duration `json:"registration_timeout,omitempty"` // How long to wait for instance registration before terminating as dangling (e.g., "5m")
DeletedRecordRetention Duration `json:"deleted_record_retention,omitempty"` // How long to keep instance records after deletion (e.g., "30m"); 0 uses default (30m)
}
GarbageCollectionConfig defines garbage collection scheduling options
type GroupConfig ¶
type GroupConfig struct {
Template string `json:"template,omitempty" validate:"required,alphanum"`
Size *int `json:"size,omitempty" validate:"omitempty,min=0"` // nil = inherit from static config
InstanceType string `json:"instance_type,omitempty"`
SubnetPool string `json:"subnet_pool,omitempty"`
Vars map[string]string `json:"vars,omitempty"`
Args map[string]interface{} `json:"args,omitempty"`
DrainTimeout *Duration `json:"drain_timeout,omitempty"` // How long to wait for drain (nil = use server default, 0 = immediate deletion)
LoadBalancers []string `json:"load_balancers,omitempty"` // References to load balancer keys
}
GroupConfig defines group configuration
func GetGroup ¶
GetGroup retrieves a group by tenant and key, merging static and dynamic configs. Returns the final merged group configuration.
func (GroupConfig) GetSize ¶
func (g GroupConfig) GetSize() int
GetSize returns the size value, defaulting to 0 if nil
type ImageConfig ¶
type ImageConfig struct {
Provider string `json:"provider" validate:"required,oneof=aws oci"` // Cloud provider (aws, oci for Oracle Cloud)
Filters []ImageFilter `json:"filters" validate:"required,min=1"` // Image filters
Owners []string `json:"owners,omitempty"` // Image owners (AWS account IDs, "self", or "amazon")
Sort string `json:"sort" validate:"required"` // Field to sort by (e.g., "creation-date", "name")
Order string `json:"order" validate:"required,oneof=asc desc"` // Sort order (asc, desc)
Fallback *string `json:"fallback,omitempty"` // Optional fallback image ID
}
ImageConfig defines configuration for automatic image lookup
type ImageFilter ¶
type ImageFilter struct {
Name string `json:"name" validate:"required"` // Filter name (e.g., "name", "owner-id")
Values []string `json:"values" validate:"required"` // Filter values
}
ImageFilter defines a filter for image lookup
type InfraConfig ¶
type InfraConfig struct {
Provider string `json:"provider" validate:"required,oneof=aws gcp mock tmux proxmox"`
Region string `json:"region" validate:"required"`
Zone string `json:"zone" validate:"required"`
Options map[string]interface{} `json:"options,omitempty"` // Provider-specific options
}
InfraConfig defines infrastructure provider configuration for the shard.
type InstanceConfig ¶
type InstanceConfig struct {
Group string `json:"group" validate:"required,alphanum"` // Required group reference
Template string `json:"template"` // Optional template override
InstanceType string `json:"instance_type"` // Optional instance type override
SubnetPool string `json:"subnet_pool"` // Optional subnet pool override
Vars map[string]string `json:"vars"` // Additional vars
}
InstanceConfig defines individual instance configuration (for on-demand instances)
type KeyConfig ¶
type KeyConfig struct {
Source string `json:"source" validate:"required,oneof=agent"` // Where the key comes from
Name string `json:"name" validate:"required"` // Name of the key
}
KeyConfig defines key reference configuration for certificates
type LeaderElectionConfig ¶
type LeaderElectionConfig struct {
Enabled *bool `json:"enabled,omitempty"` // Default: true. Use pointer to distinguish unset from false
FrequentInterval Duration `json:"frequent_interval,omitempty"` // Polling interval during transitions (default: 5s)
InfrequentInterval Duration `json:"infrequent_interval,omitempty"` // Polling interval during stable periods (default: 30s)
LeaderTimeout Duration `json:"leader_timeout,omitempty"` // Time before considering leader failed (default: 15s)
}
LeaderElectionConfig defines leader election timing options. Used for both cluster and shard leader election.
type LeaderNetworkConfig ¶
type LeaderNetworkConfig struct {
IP string `json:"ip,omitempty"` // Stable leader IP address (ENI private IP for AWS, reserved IP for GCP)
InterfaceID string `json:"interface_id,omitempty"` // Provider resource ID: ENI ID for AWS; empty for GCP (which uses alias IP)
}
LeaderNetworkConfig defines stable leader network configuration for shard leadership. This enables a stable IP address to be assigned when acquiring leadership.
type LoadBalancerConfig ¶
type LoadBalancerConfig struct {
Provider string `json:"provider" validate:"required,oneof=aws gcp"`
// AWS-specific fields
TargetGroupArns []string `json:"target_group_arns,omitempty"` // Multiple ARNs for multi-port NLBs
// GCP-specific fields
BackendServiceName *string `json:"backend_service_name,omitempty"`
InstanceGroupName *string `json:"instance_group_name,omitempty"`
}
LoadBalancerConfig defines load balancer configuration
type Loader ¶
type Loader struct {
// contains filtered or unexported fields
}
Loader handles loading and caching of configuration from storage.
The loader uses a two-tier caching strategy:
- In-memory cache: fastest access for runtime operations
- Disk cache: persists across process restarts to minimize S3 reads
The disk cache is critical for cost control - if the server enters a crash loop or restarts frequently, it prevents excessive S3 GET requests which could become expensive at scale. On startup, we first check the disk cache before hitting S3.
The loader expects to receive shard-scoped storage - all paths are relative to the shard scope (e.g., "config.jsonc" not "shard/{shard}/config.jsonc").
func NewLoader ¶
func NewLoader(opts LoaderOptions) (*Loader, error)
NewLoader creates a new configuration loader. Storage and CacheStorage should be scoped to the shard - the loader uses relative paths like "config.jsonc" and "groups.jsonc".
func (*Loader) CleanCache ¶
CleanCache removes all cached files (config and groups)
func (*Loader) DeleteDynamicGroup ¶
DeleteDynamicGroup atomically removes a dynamic group and persists to S3.
func (*Loader) GetCurrent ¶
GetCurrent returns the currently loaded configuration
func (*Loader) GetDynamicGroup ¶
func (l *Loader) GetDynamicGroup(tenant, key string) (GroupConfig, bool)
GetDynamicGroup returns a dynamic group from the in-memory cache for a specific tenant Returns empty config and false if not found, not loaded, or tenant is empty This method never triggers disk or S3 reads
func (*Loader) GetMetadata ¶
func (l *Loader) GetMetadata() *ConfigMetadata
GetMetadata returns the metadata of the currently loaded configuration
func (*Loader) LoadConfigAndGroups ¶
LoadConfigAndGroups loads the configuration and dynamic groups from storage. If forceRefresh is false, it will use local cache if available (faster startup). If forceRefresh is true, it always downloads from S3 (for explicit refresh). After loading, it syncs all groups to SQLite for runtime operations.
func (*Loader) LoadDynamicGroups ¶
LoadDynamicGroups loads dynamic groups from S3 groups.jsonc. Returns the cached map for read-only access. Do not mutate the returned map; use SetDynamicGroup/DeleteDynamicGroup for mutations.
func (*Loader) RefreshGroups ¶
RefreshGroups forces a refresh of the dynamic groups from storage
func (*Loader) SetDynamicGroup ¶
SetDynamicGroup atomically updates a single dynamic group and persists to S3. This is the only safe way to mutate dynamic groups. Uses ETag from disk cache to prevent concurrent modification. Updates both in-memory and disk cache on successful write.
func (*Loader) SyncGroupsToCache ¶
SyncGroupsToCache syncs all effective groups to SQLite with computed hashes. This should be called after config or groups are loaded/reloaded. Groups cannot exist in SQLite without hashes - they are computed and stored atomically.
type LoaderOptions ¶
type LoaderOptions struct {
Storage storage.Storage // Main storage (e.g. S3), scoped to shard
CacheStorage storage.Storage // Cache storage (e.g. local filesystem), scoped to shard
LocalDB *localdb.DB // Local SQLite database for caching groups with hashes
Logger *slog.Logger
MaxRetries *int // Maximum retry attempts (nil = use default)
AdvertiseHost string // CLI override for advertise health/election host (empty = use auto-detection)
}
LoaderOptions contains options for creating a new Loader
type MergedConfig ¶
type MergedConfig struct {
Args map[string]interface{} `json:"args"`
Vars map[string]string `json:"vars"`
Files map[string]FileConfig `json:"files"`
Userdata *UserdataConfig `json:"userdata,omitempty"`
InstanceType string `json:"instance_type"`
SubnetPool string `json:"subnet_pool"`
Kind string `json:"kind"`
Arch string `json:"arch"`
}
MergedConfig represents a fully resolved configuration after merging
type SecretsConfig ¶
type SecretsConfig struct {
Provider string `json:"provider" validate:"required,oneof=object-storage aws-secrets-manager gcp-secret-manager memory"`
Prefix string `json:"prefix,omitempty"` // Prefix for secrets (S3 path or AWS name prefix)
EncryptionKey *EncryptionKeyConfig `json:"encryption_key,omitempty"` // Current key (used for encryption)
OldEncryptionKeys []EncryptionKeyConfig `json:"old_encryption_keys,omitempty"` // Old keys (decryption only during rotation)
CacheTTL Duration `json:"cache_ttl,omitempty"` // Cache TTL for secrets, 0 disables caching
}
SecretsConfig defines secrets management configuration
type ShardConfig ¶
type ShardConfig struct {
ID string `json:"id" validate:"required"`
Infra InfraConfig `json:"infra" validate:"required"`
Bind BindConfig `json:"bind" validate:"required"`
Advertise AdvertiseConfig `json:"advertise" validate:"required"`
LeaderNetwork *LeaderNetworkConfig `json:"leader_network,omitempty"`
RequestTimeout Duration `json:"request_timeout,omitempty"`
CreateRateLimit Duration `json:"create_rate_limit,omitempty"`
HealthCheckInterval Duration `json:"health_check_interval,omitempty"`
DefaultDrainTimeout Duration `json:"default_drain_timeout,omitempty"`
ImageRefreshInterval Duration `json:"image_refresh_interval,omitempty"`
ShutdownTimeout Duration `json:"shutdown_timeout,omitempty"`
SubnetPools map[string][]string `json:"subnet_pools"`
DynamicSubnetPools []string `json:"dynamic_subnet_pools"`
GarbageCollection GarbageCollectionConfig `json:"garbage_collection"`
Expiry ExpiryConfig `json:"expiry"`
LeaderElection LeaderElectionConfig `json:"leader_election"`
ErrorExitJitter ErrorExitJitterConfig `json:"error_exit_jitter"`
}
ShardConfig defines shard-specific configuration for a single shard server.
type TemplateConfig ¶
type TemplateConfig struct {
Kind string `json:"kind" validate:"required,len=3,lowercase,alpha"`
Arch string `json:"arch" validate:"required,oneof=amd64 arm64"`
Files map[string]FileConfig `json:"files"` // fileName -> FileConfig mapping
Args map[string]interface{} `json:"args"`
Userdata *UserdataConfig `json:"userdata,omitempty"`
Size int `json:"size" validate:"min=0"`
InstanceType string `json:"instance_type"`
SubnetPool string `json:"subnet_pool"`
Vars map[string]string `json:"vars"`
}
TemplateConfig defines instance template configuration
type TenantGroup ¶
type TenantGroup struct {
Tenant string
Key string
Config GroupConfig
}
TenantGroup represents a group with its tenant context
func GetAllGroups ¶
func GetAllGroups(ctx context.Context, loader *Loader) ([]TenantGroup, error)
GetAllGroups returns all groups across all tenants, merging static and dynamic configs Returns a slice of TenantGroup containing tenant, group key, and merged config
type UserdataConfig ¶
type UserdataConfig struct {
Source string `json:"source,omitempty"` // "inline" (default) or "url"
Encoding string `json:"encoding,omitempty"` // "plain" (default), "base64", "gzip", "base64+gzip"
Content string `json:"content" validate:"required"`
}
UserdataConfig defines userdata configuration for instance templates
func (*UserdataConfig) Validate ¶
func (u *UserdataConfig) Validate() error
Validate validates the UserdataConfig