Documentation
¶
Overview ¶
Package configgcpparameter contributes configuration from Google Cloud Parameter Manager as a first-class config layer: precedence, per-key merge, provenance and safe hot-reload, exactly like a file layer.
Parameter Manager is GCP's purpose-built store for workload parameters — application configuration as versioned key-value data — not the deprecated Runtime Configurator and not Secret Manager, which holds secrets. This adapter is therefore configuration, read-only, and not sensitive: it returns the raw, unrendered payload and never resolves Secret Manager references, so no secret enters a layer. See the config-gcp-parameter spec, D2 and D5.
Two data-model modes select how one or many parameters become a layer:
- Single-document (default, New/FromClient): one named parameter's current version payload is the whole layer's source document, decoded into the nested tree through an injected config.Codec (WithValueCodec).
- Prefix mode (NewPrefix/FromClientPrefix): every parameter whose id begins with a prefix is scanned and nested as a leaf — the Consul-shaped model — at one payload fetch per matching parameter.
Parameter Manager carries a declared Format field (Unformatted, YAML, JSON), surfaced on Parameter for diagnostics, but it never selects a codec: decoding is driven by an explicitly injected config.Codec only, so this module takes no codec dependency of its own (spec D4). A payload the codec rejects stays a scalar string, so enabling a codec never turns a value into a load error.
The service is reached through the narrow PM interface, which Wrap adapts from a configured *parametermanager.Client. Injecting the client keeps every credential, project, location, endpoint and scope decision with the consumer and lets the whole unit suite run against a fake, needing no GCP.
Index ¶
- Constants
- Variables
- func FromClient(client *parametermanager.Client, project, location, parameter string, ...) config.Backend
- func FromClientPrefix(client *parametermanager.Client, project, location, prefix string, ...) config.Backend
- func New(pm PM, parameter string, opts ...Option) config.Backend
- func NewPrefix(pm PM, prefix string, opts ...Option) config.Backend
- type Format
- type Option
- type OwnedBackend
- func Default(ctx context.Context, project, location, parameter string, opts ...Option) (*OwnedBackend, error)
- func DefaultPrefix(ctx context.Context, project, location, prefix string, opts ...Option) (*OwnedBackend, error)
- func FromOptions(ctx context.Context, project, location, parameter string, ...) (*OwnedBackend, error)
- func FromOptionsPrefix(ctx context.Context, project, location, prefix string, ...) (*OwnedBackend, error)
- type PM
- type Parameter
Examples ¶
Constants ¶
const SourceKind = config.SourceKind("gcpparameter")
SourceKind is what a Parameter Manager layer reports as, so provenance can name it — a value renders as "gcpparameter:projects/.../versions/3".
Variables ¶
var ( // ErrNoProject reports a rung called with no project id. Unlike a region on // AWS there is no ambient convention that can supply one: Application Default // Credentials authenticate a principal, they do not name the project whose // parameters to read. ErrNoProject = errors.NewSentinel("configgcpparameter.no_project", "no Google Cloud project supplied; pass the project the parameters live in") // ErrNoLocation reports a rung called with no location. // // Parameter Manager, unlike Secret Manager, has no project-level parent: every // parameter lives under a location, and "global" is the ordinary one. An empty // location would address nothing. ErrNoLocation = errors.NewSentinel("configgcpparameter.no_location", `no Google Cloud location supplied; pass "global" unless the parameters are regionalised`) )
Functions ¶
func FromClient ¶
func FromClient(client *parametermanager.Client, project, location, parameter string, opts ...Option) config.Backend
FromClient is the common single-document path: New over a Wrap-ped Parameter Manager client, so a consumer writes configgcpparameter.FromClient(client, "my-proj", "global", "app-config") without touching the narrow interface.
Example ¶
ExampleFromClient reads a single configuration document from GCP Parameter Manager. You build and configure the client — project, credentials, and (for a regional parameter) the endpoint all stay yours — and hand it in with the project, location and parameter id. A value codec decodes the parameter's JSON or YAML payload into the nested tree.
package main
import (
"context"
"fmt"
"log"
parametermanager "cloud.google.com/go/parametermanager/apiv1"
"gitlab.com/phpboyscout/go/config"
configjson "gitlab.com/phpboyscout/go/config-json"
configgcpparameter "gitlab.com/phpboyscout/go/config-gcp-parameter"
)
func main() {
ctx := context.Background()
client, err := parametermanager.NewClient(ctx)
if err != nil {
log.Fatal(err)
}
store, err := config.NewStore(ctx,
config.WithBackend(configgcpparameter.FromClient(client, "my-proj", "global", "app-config",
configgcpparameter.WithValueCodec(configjson.Codec{}))),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(store.View().GetInt("server.port"))
}
Output:
func FromClientPrefix ¶
func FromClientPrefix(client *parametermanager.Client, project, location, prefix string, opts ...Option) config.Backend
FromClientPrefix is the common prefix-mode path: NewPrefix over a Wrap-ped client, scanning every parameter under prefix.
Example ¶
ExampleFromClientPrefix reads many small parameters under a prefix, nesting each as a leaf: app-server-host and app-server-port become server.host and server.port.
package main
import (
"context"
"fmt"
"log"
parametermanager "cloud.google.com/go/parametermanager/apiv1"
"gitlab.com/phpboyscout/go/config"
configgcpparameter "gitlab.com/phpboyscout/go/config-gcp-parameter"
)
func main() {
ctx := context.Background()
client, err := parametermanager.NewClient(ctx)
if err != nil {
log.Fatal(err)
}
store, err := config.NewStore(ctx,
config.WithBackend(configgcpparameter.FromClientPrefix(client, "my-proj", "global", "app-")),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(store.View().GetString("server.host"))
}
Output:
func New ¶
New returns a backend contributing one named parameter's current version as a config layer — single-document mode (spec D3a, the default). pm is the injected client — a fake in tests, a Wrap-ped client in production; parameter is the parameter id, resolved to its latest enabled version at Load.
Types ¶
type Format ¶
type Format int
Format mirrors the service's immutable ParameterFormat, so the adapter never exposes the raw protobuf enum. It is surfaced for diagnostics and provenance but never used to pick a codec (spec D4).
type Option ¶
type Option func(*backend)
Option configures a backend.
func WithPollInterval ¶
WithPollInterval sets this backend's own poll cadence — how often config.WatchableBackend Watch re-resolves the change fingerprint. It is also the cadence the backend advertises through config.PollIntervalHinter, so a default config.Store.Watch adopts it; an explicit config.WithPollInterval on the Store still overrides it. Omitted, the default is 60s, deliberately conservative because each tick is a billed API call (spec D7).
func WithValueCodec ¶
WithValueCodec decodes a parameter's payload through codec: a payload that decodes to a mapping becomes a subtree (in single-document mode, the whole layer's tree; in prefix mode, that parameter's leaf), and a payload the codec rejects — a bare scalar, or bytes that are not a document — stays a scalar string, so a store mixing documents and scalars reads correctly. Omitted, every payload is a scalar string.
codec is any config.Codec — the interface the sibling format adapters implement — so a JSON-document store is read with configjson.Codec{} and a YAML-document store with the core's, and this module takes no codec dependency of its own (spec D4).
type OwnedBackend ¶ added in v0.3.0
OwnedBackend is a backend that built its own Parameter Manager client and is therefore responsible for closing it.
parametermanager.NewClient opens a gRPC connection, returns an error, and its own documentation says the client "must be Closed when it is done being used to clean up its underlying connections". config.Backend has no Close, and a Store drops a withdrawn backend without teardown, so a client an adapter resolved for itself would otherwise live for the whole process.
A one-shot CLI can ignore Close and let process exit reclaim it. A long-lived service that adds and withdraws backends should not:
b, err := configgcpparameter.Default(ctx, "my-project", "global", "app-config")
if err != nil { return err }
defer b.Close()
store, err := config.NewStore(ctx, config.WithBackend(b))
The rungs that do NOT build a client — New, NewPrefix, Wrap, FromClient and FromClientPrefix — return a plain config.Backend, because there the consumer built it and still owns it (spec 0012 L-7, R2).
func Default ¶ added in v0.3.0
func Default( ctx context.Context, project, location, parameter string, opts ...Option, ) (*OwnedBackend, error)
Default builds a client from Application Default Credentials — the metadata server, a workload identity, GOOGLE_APPLICATION_CREDENTIALS, or gcloud's own login — and returns a single-parameter backend that owns it.
This is the zero-conf rung. Unlike its AWS and Azure counterparts it still needs the project and location, because ADC authenticates a principal without naming the parameters to read; guessing would read another project's.
The returned backend owns the client and must be Closed; see OwnedBackend.
func DefaultPrefix ¶ added in v0.3.0
func DefaultPrefix( ctx context.Context, project, location, prefix string, opts ...Option, ) (*OwnedBackend, error)
DefaultPrefix is Default for the prefix shape.
func FromOptions ¶ added in v0.3.0
func FromOptions( ctx context.Context, project, location, parameter string, clientOpts []option.ClientOption, opts ...Option, ) (*OwnedBackend, error)
FromOptions builds a client from client options the caller holds — an explicit credentials file, an emulator endpoint, or a credential resolved once with go/gcpclient and shared across the GCP siblings — and returns a single-parameter backend that owns it.
The returned backend owns the client and must be Closed; see OwnedBackend.
func FromOptionsPrefix ¶ added in v0.3.0
func FromOptionsPrefix( ctx context.Context, project, location, prefix string, clientOpts []option.ClientOption, opts ...Option, ) (*OwnedBackend, error)
FromOptionsPrefix is FromOptions for the prefix shape: every parameter under the prefix becomes one layer.
func (*OwnedBackend) Close ¶ added in v0.3.0
func (b *OwnedBackend) Close() error
Close releases the Parameter Manager client this backend built. It is safe to call more than once.
type PM ¶
type PM interface {
// Get returns one parameter's declared format and current (latest enabled)
// version — its resource name and raw payload bytes. A parameter or version
// that does not exist returns fs.ErrNotExist. Drives single-document mode.
Get(ctx context.Context, parameter string) (Parameter, error)
// List returns every parameter whose id begins with prefix, each resolved to
// its current version — id, format, version name and raw payload. An empty
// result is not an error. Drives prefix mode; it is the fan-out whose
// per-parameter payload fetch is the honest cost of that mode.
List(ctx context.Context, prefix string) ([]Parameter, error)
}
PM is the slice of Parameter Manager this adapter uses, behind an interface it owns so a fake drives the unit suite and the real client is adapted by Wrap. Read-only (spec D5): there is no write method.
func Wrap ¶
func Wrap(client *parametermanager.Client, project, location string) PM
Wrap adapts a configured Parameter Manager SDK client to the narrow PM interface. The client carries every credential, scope and — for a regional parameter — endpoint decision; Wrap adds none. project and location compose the resource path; location is the segment the consumer's client endpoint must match (spec D6, D8), which the adapter trusts rather than validates.
type Parameter ¶
type Parameter struct {
// ID is the parameter id (the last path segment), for prefix-mode nesting.
ID string
// Format is the format the parameter declares — informational only.
Format Format
// VersionName is the full version resource name — the watch change
// fingerprint and the layer's provenance.
VersionName string
// Payload is the raw, unrendered version payload bytes.
Payload []byte
}
Parameter is one resolved read: the parameter's id, the format it declares (surfaced but not used to pick a codec), and its current version.