Documentation
¶
Overview ¶
Example ¶
Example demonstrates how to use go-skyconf to parse configuration from AWS SSM.
This example assumes you have a working AWS session and SSM client. It also assumes that the following parameters exist in AWS SSM under the path /myapplication/:
- app/name: "MyApp"
- app/version: "1.2.3"
- db/host: "localhost"
- db/port: "5432"
- log_level: "info"
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ssm"
sky "github.com/redmatter/go-skyconf"
)
func main() {
// 1. Define your configuration struct.
// Use struct tags to control how fields are populated from SSM.
type Config struct {
App struct {
Name string `sky:"name"`
Version string `sky:"version"`
} `sky:"app"`
Database struct {
Host string `sky:"host"`
Port int `sky:"port"`
} `sky:"db"`
LogLevel string `sky:"log_level,optional"`
}
// 2. Set up a real SSM client from the AWS SDK.
// In a real application, you would load the default AWS config.
awsCfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Printf("unable to load SDK config, %v; skipping example", err)
return
}
ssmClient := ssm.NewFromConfig(awsCfg)
// 3. Define the SSM source for your configuration.
// This tells go-skyconf where to look for parameters.
ssmSource := sky.SSMSource(ssmClient, "/myapplication/")
// 4. Create an instance of your config struct and parse the configuration.
var cfg Config
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_, err = sky.Parse(ctx, &cfg, false, ssmSource)
if err != nil {
// This will fail if the parameters don't exist in SSM.
log.Printf("failed to parse configuration: %v; skipping example", err)
return
}
// 5. Your config struct is now populated.
fmt.Printf("AppName: %s\n", cfg.App.Name)
fmt.Printf("AppVersion: %s\n", cfg.App.Version)
fmt.Printf("DB Host: %s\n", cfg.Database.Host)
fmt.Printf("DB Port: %d\n", cfg.Database.Port)
fmt.Printf("Log Level: %s\n", cfg.LogLevel)
}
Output: AppName: MyApp AppVersion: 1.2.3 DB Host: localhost DB Port: 5432 Log Level: info
Example (MultipleSources) ¶
Example demonstrates how to use go-skyconf to parse configuration from multiple hierarchical sources in AWS SSM.
This example assumes a working AWS session and that the following parameters exist in AWS SSM:
Project-level parameters under /my-project/:
- db/host: "project-db.example.com"
- db/port: "5432"
App-level parameters under /my-project/apps/my-app/:
- log_level: "debug"
- app_name: "MyAwesomeApp"
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ssm"
sky "github.com/redmatter/go-skyconf"
)
func main() {
// 1. Define your configuration struct with source tags.
type Config struct {
Database struct {
Host string `sky:"host"`
Port int `sky:"port"`
} `sky:"db,source:project"` // From project source
App struct {
LogLevel string `sky:"log_level"`
} `sky:",flatten,source:app"` // From app source
AppName string `sky:"app_name,source:app"` // From app source
}
// 2. Set up a real SSM client.
awsCfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Printf("unable to load SDK config, %v; skipping example", err)
return
}
ssmClient := ssm.NewFromConfig(awsCfg)
// 3. Define multiple SSM sources with unique IDs.
projectSource := sky.SSMSourceWithID(ssmClient, "/my-project/", "project")
appSource := sky.SSMSourceWithID(ssmClient, "/my-project/apps/my-app/", "app")
// 4. Parse the configuration using both sources.
var cfg Config
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_, err = sky.Parse(ctx, &cfg, false, projectSource, appSource)
if err != nil {
log.Printf("failed to parse configuration: %v; skipping example", err)
return
}
// 5. Your config struct is now populated from multiple sources.
fmt.Printf("DB Host: %s\n", cfg.Database.Host)
fmt.Printf("DB Port: %d\n", cfg.Database.Port)
fmt.Printf("Log Level: %s\n", cfg.App.LogLevel)
fmt.Printf("AppName: %s\n", cfg.AppName)
}
Output: DB Host: project-db.example.com DB Port: 5432 Log Level: debug AppName: MyAwesomeApp
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrBadDefaultFieldValue = errors.New("failed to set default value for field")
ErrBadDefaultFieldValue is returned when a specified default value could not be set for a field.
var ErrBadFieldValue = errors.New("failed to set value for field")
ErrBadFieldValue is returned when a value could not be set for a field.
var ErrBadTags = errors.New("error parsing tags for field")
var ErrGetParameters = errors.New("failed to get parameters")
ErrGetParameters is returned when no parameters could not be fetched from a source.
var ErrInvalidStruct = errors.New("config must be a pointer to a struct")
var ErrMissingKeyOnRefresh = errors.New("missing key on refresh")
var ErrNoSource = errors.New("no sources provided")
ErrNoSource is returned when no sources are provided to the Parse function.
var ErrParameterNotFound = errors.New("parameter not found in source")
ErrParameterNotFound is returned when a parameter is not found in the source.
var ErrSourceNotFound = errors.New("source not found")
ErrSourceNotFound is returned when a specified source was not found in the list of sources.
var ErrSourceNotRefreshable = errors.New("source is not refreshable")
Functions ¶
func String ¶
func String(cfg interface{}, withUntagged bool, withCurrentValue bool, sources ...Source) (str string, err error)
String returns a string representation of the provided configuration struct, describing source and parameter name for each field. If withCurrentValue is true, the current value of the field is also included.
func ToSnakeCase ¶
Types ¶
type Refresher ¶ added in v1.1.0
type Refresher interface {
// Refresh starts a new goroutine that updates the configuration at specified intervals until the context is
// cancelled. It returns a channel that sends updated field IDs. If an error occurs, the provided error function is
// called. If no error function is provided, the error is ignored.
Refresh(ctx context.Context, ef func(err error)) <-chan string
// RefreshOnce refreshes the configuration once, returning the first error that occurs.
RefreshOnce(ctx context.Context) (err error)
}
Refresher refreshes configuration at specified intervals.
Example ¶
package main
import (
"context"
"log"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/service/ssm"
sky "github.com/redmatter/go-skyconf"
)
func main() {
// This example is for documentation purposes and is not runnable as a standalone test
// as it requires a pre-configured SSM client and parameters in AWS SSM.
// For a more complete example, see Example().
// Initialise SSM client using aws-sdk-go-v2
var ssmClient *ssm.Client
// Create a timeout context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
cfg := struct {
LogLevel string
DB struct {
Host string `sky:"host"`
Port int `sky:"port"`
Username string `sky:"username"`
Password string `sky:"password"`
} `sky:",flatten"`
EnabledProductIDs string `sky:"enabled_list,refresh=5m,id=enabled_product_list"`
}{}
// Parse database configuration from SSM
refresher, err := sky.Parse(ctx, &cfg, false, sky.SSMSource(ssmClient, os.Getenv("APP_SSM_PATH")+"database/"))
if err != nil {
log.Fatalln("failed to parse configuration:", err)
}
// Refresh the configuration according to the timings specified in the struct tags.
// In this case, the `enabled_list` field will be refreshed every 5 minutes.
updates := refresher.Refresh(ctx, func(err error) {
if err != nil {
log.Println("error refreshing configuration:", err)
}
})
go func() {
for update := range updates {
log.Println("updated field:", update)
switch update {
case "enabled_product_list": // The ID specified in the struct tag
// Do something with the updated field
default:
// This should never happen unless a new field is added.
log.Fatalln("unknown field updated:", update)
}
}
}()
// Use the configuration
// When done, cancel the context to stop the refresh
cancel()
}
Output:
func Parse ¶
func Parse(ctx context.Context, cfg interface{}, withUntagged bool, sources ...Source) (r Refresher, err error)
Parse fetches configuration from the provided sources into the given struct. If a source is specified for a field, its value is queried only from that source. Otherwise, all sources are queried in order, with the last source's value taking precedence. Fields not tagged with `sky` are ignored unless `withUntagged` is true. Returns a Refresher for automatic configuration refresh.
The configuration struct must have fields tagged with `sky` and the following tags. All tags are optional.
- default: sets the default value for the field.
- optional: marks the field as optional, suppressing errors if the field is not found in the source.
- flatten: flattens the field thereby ignoring the key of the outer struct.
- source: specifies the source for the field.
- refresh: sets the refresh duration for the field; duration must be in Go time.Duration format and greater than 0.
- id: sets the identifier for the field, used for update notifications.
Example ¶
ExampleParse demonstrates how to use the Parse function to parse configuration from AWS SSM.
package main
import (
"context"
"log"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/service/ssm"
sky "github.com/redmatter/go-skyconf"
)
func main() {
// This example is for documentation purposes and is not runnable as a standalone test
// as it requires a pre-configured SSM client and parameters in AWS SSM.
// For a more complete example, see Example().
// Initialise SSM client using aws-sdk-go-v2
var ssmClient *ssm.Client
// Create a timeout context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cfg := struct {
LogLevel string
DB struct {
Host string `sky:"host"`
Port int `sky:"port"`
Username string `sky:"username"`
Password string `sky:"password"`
} `sky:",flatten"`
}{}
// Parse database configuration from SSM
_, err := sky.Parse(ctx, &cfg, false, sky.SSMSource(ssmClient, os.Getenv("APP_SSM_PATH")+"database/"))
if err != nil {
log.Fatalln("failed to parse configuration:", err)
}
// Use the configuration
}
Output:
type Source ¶
type Source interface {
// Source fetches the parameters from the source.
Source(ctx context.Context, params []string) (values map[string]string, err error)
// ParameterName formats the parameter name.
ParameterName(parts []string) string
// Refreshable returns true if the source is refreshable.
Refreshable() bool
// ID returns the ID of the source.
ID() string
}
Source can format a parameter name and fetch a set of parameters from a source.