Documentation
¶
Overview ¶
Package binding is the SDK for OpenRun binding providers: out-of-process plugins that implement service bindings (account and grant management on external services like databases). A provider implements the ServiceBinding interface for one or more service types and calls Serve from its main function. The OpenRun server launches the provider executable on demand and communicates with it over gRPC using hashicorp/go-plugin.
This package is a separate Go module so that providers only depend on the SDK's small dependency tree, not on the OpenRun server. It is distinct from the server embedding API in pkg/api.
Index ¶
- Constants
- Variables
- func AccountName(prefixProd, prefixStg, bindingId string, isStaging bool, opts NameOptions) (string, error)
- func AccountURLs(adminURL, user, password, bindingHostname string) (accountURL, accountDirectURL string, err error)
- func DiffGrants(currentGrants []BindingGrant, newGrants []BindingGrant) ([]BindingGrant, []BindingGrant)
- func IsLocalBindingHost(host string) bool
- func RandomHex(n int) (string, error)
- func RevokeThenRegrant(revokes, regrants []BindingGrant, ...) error
- func Serve(config *ServeConfig)
- func ServiceConfigWithLocalhostBindingHostname(serviceConfig map[string]string, serviceURL string, ...) map[string]string
- func SetURLHostname(u *url.URL, hostname string)
- func VerifyKeys(inputKeys []string, requiredKeys []string, optionalKeys []string) error
- type Artifact
- type ArtifactType
- type BindingGrant
- type BindingMetadata
- type Builder
- type Client
- func (c *Client) ApplyGrants(ctx context.Context, account map[string]string, ...) (GrantApplyResult, error)
- func (c *Client) CloseService(ctx context.Context) error
- func (c *Client) DeleteArtifact(ctx context.Context, artifact Artifact) error
- func (c *Client) Describe(ctx context.Context) (string, []ServiceTypeInfo, error)
- func (c *Client) GenerateAccount(ctx context.Context, bindingId, bindingPath string, ...) (map[string]string, []Artifact, error)
- func (c *Client) GetAccountEnv(ctx context.Context, serviceType string) ([]string, []string, error)
- func (c *Client) InitializeService(ctx context.Context, serviceType string, serviceConfig map[string]string, ...) error
- func (c *Client) RevokeGrants(ctx context.Context, account map[string]string, ...) error
- func (c *Client) RunCommand(ctx context.Context, bindingMetadata BindingMetadata, command string) (map[string]any, error)
- type GrantApplyResult
- type GrantType
- type LaunchConfig
- type Logger
- type NameOptions
- type Provider
- func (p *Provider) ApplyGrants(ctx context.Context, account map[string]string, ...) (GrantApplyResult, error)
- func (p *Provider) CloseService(ctx context.Context) error
- func (p *Provider) DeleteArtifact(ctx context.Context, artifact Artifact) error
- func (p *Provider) Describe(ctx context.Context) (string, []ServiceTypeInfo, error)
- func (p *Provider) Exited() bool
- func (p *Provider) GenerateAccount(ctx context.Context, bindingId, bindingPath string, ...) (map[string]string, []Artifact, error)
- func (p *Provider) GetAccountEnv(ctx context.Context, serviceType string) ([]string, []string, error)
- func (p *Provider) InitializeService(ctx context.Context, serviceType string, serviceConfig map[string]string, ...) error
- func (p *Provider) Kill()
- func (p *Provider) RevokeGrants(ctx context.Context, account map[string]string, ...) error
- func (p *Provider) RunCommand(ctx context.Context, bindingMetadata BindingMetadata, command string) (map[string]any, error)
- type ProviderError
- type ServeConfig
- type ServiceBinding
- type ServiceBindingRuntime
- type ServiceTypeInfo
Constants ¶
const ( AccountKeyURL = "url" AccountKeyURLDirect = "url_direct" )
Account map keys common to all bindings. AccountKeyURL is the connection URL apps use (with the localhost binding hostname applied when apps run in containers); AccountKeyURLDirect keeps the service hostname and is used for server-side connections like RunCommand.
const BindingHostnameDisable = "disable"
const BindingIDPrefix = "bnd_"
BindingIDPrefix is the prefix of binding ids as generated by the server. Bindings strip it when deriving account object names to stay within database identifier length limits.
const (
GrantTargetAll = "*"
)
const PluginName = "binding"
PluginName is the go-plugin dispense name for the binding provider plugin.
const ProtocolVersion = 1
ProtocolVersion is the go-plugin protocol version for the v1 binding provider protocol. Incompatible protocol changes bump this and are served side by side through VersionedPlugins during a transition.
Variables ¶
var Handshake = plugin.HandshakeConfig{ ProtocolVersion: ProtocolVersion, MagicCookieKey: "OPENRUN_BINDING_PROVIDER", MagicCookieValue: "5c3f7a1e-openrun-binding-provider", }
Handshake is the go-plugin handshake shared by the server and providers. The magic cookie is a sanity check that the launched executable is a binding provider, not a security measure.
Functions ¶
func AccountName ¶
func AccountName(prefixProd, prefixStg, bindingId string, isStaging bool, opts NameOptions) (string, error)
AccountName builds an account object name (user/role/schema/login) from the binding id: the prod or staging prefix followed by the binding id with its bnd_ prefix stripped (unless KeepIDPrefix is set).
func AccountURLs ¶
func AccountURLs(adminURL, user, password, bindingHostname string) (accountURL, accountDirectURL string, err error)
AccountURLs builds the account connection URL pair from the admin URL: url has the binding hostname applied (empty or "disable" leaves the host unchanged), urlDirect always keeps the service hostname.
func DiffGrants ¶
func DiffGrants(currentGrants []BindingGrant, newGrants []BindingGrant) ([]BindingGrant, []BindingGrant)
DiffGrants returns the grants to revoke (in currentGrants but not newGrants) and the grants to apply (in newGrants but not currentGrants).
func IsLocalBindingHost ¶
IsLocalBindingHost reports whether host refers to the local host.
func RevokeThenRegrant ¶
func RevokeThenRegrant(revokes, regrants []BindingGrant, perms func(op string, grants []BindingGrant) error) error
RevokeThenRegrant is the RevokeGrants scaffolding for incremental bindings: execute the revokes, then re-apply the grants that must remain, because a revoke at the same scope removes privileges the remaining grants still need (e.g. revoking full:t1 while read:t1 remains drops the shared SELECT on t1). perms executes one grant or revoke batch; op is "grant" or "revoke".
func Serve ¶
func Serve(config *ServeConfig)
Serve runs the provider plugin. It is called from a provider executable's main function and blocks until the server side closes the plugin. The OPENRUN_PROVIDER_LOG_LEVEL environment variable (set by the server from its own log level) controls provider log verbosity.
func ServiceConfigWithLocalhostBindingHostname ¶
func ServiceConfigWithLocalhostBindingHostname(serviceConfig map[string]string, serviceURL string, runtime ServiceBindingRuntime) map[string]string
ServiceConfigWithLocalhostBindingHostname returns the service config with binding_hostname defaulted to the runtime's localhost binding hostname when the service URL points at localhost and no explicit binding_hostname is set.
func SetURLHostname ¶
SetURLHostname replaces the hostname in u, preserving the port. A hostname of "" or "disable" leaves the URL unchanged.
Types ¶
type Artifact ¶
type Artifact struct {
Type ArtifactType
Name string
}
Artifact identifies one object created on the service by GenerateAccount, such as a role/schema (postgres) or user/database (mysql). The caller tracks the created artifacts and passes them back to DeleteArtifact to undo the creation on rollback.
type ArtifactType ¶
type ArtifactType string
const ( ArtifactRole ArtifactType = "role" ArtifactSchema ArtifactType = "schema" ArtifactUser ArtifactType = "user" ArtifactDatabase ArtifactType = "database" ArtifactLogin ArtifactType = "login" // SQL Server server-level login backing a database user )
type BindingGrant ¶
type BindingGrant struct {
GrantType GrantType `json:"grant_type"`
GrantTarget string `json:"grant_target"`
}
func ParseGrant ¶
func ParseGrant(grant string, supportedGrantTypes []GrantType) (BindingGrant, error)
ParseGrant parses a "type:target" grant string, verifying the type against the service's supported grant types.
func ParseGrants ¶
func ParseGrants(grants []string, supportedGrantTypes []GrantType) ([]BindingGrant, error)
ParseGrants parses a list of "type:target" grant strings.
func SubtractGrants ¶
func SubtractGrants(list, remove []BindingGrant) []BindingGrant
SubtractGrants returns the grants in list that are not in remove, preserving order.
func UnionGrants ¶
func UnionGrants(base, extra []BindingGrant) []BindingGrant
UnionGrants returns base plus any grants from extra not already present, preserving order.
func (BindingGrant) String ¶
func (g BindingGrant) String() string
type BindingMetadata ¶
type BindingMetadata struct {
Grants []string `json:"grants"`
GrantsApplied []BindingGrant `json:"grants_applied"`
Config map[string]string `json:"config"`
Account map[string]string `json:"account,omitempty"`
ApplyInfo []byte `json:"apply_info"`
}
BindingMetadata is the metadata of one binding entry, as stored by the OpenRun server and passed to provider calls.
type Builder ¶
type Builder func() ServiceBinding
Builder creates a new, uninitialized ServiceBinding instance.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the typed gRPC client for the provider protocol, dispensed by go-plugin. Server code uses Provider, which wraps process lifecycle around it.
func (*Client) ApplyGrants ¶
func (c *Client) ApplyGrants(ctx context.Context, account map[string]string, bindingMetadata, derivedFromMetadata BindingMetadata, reapplyAll bool) (GrantApplyResult, error)
func (*Client) DeleteArtifact ¶
func (*Client) GenerateAccount ¶
func (*Client) GetAccountEnv ¶
func (*Client) InitializeService ¶
func (*Client) RevokeGrants ¶
func (c *Client) RevokeGrants(ctx context.Context, account map[string]string, derivedFromMetadata BindingMetadata, revokes, regrants []BindingGrant) error
func (*Client) RunCommand ¶
type GrantApplyResult ¶
type GrantApplyResult struct {
// GrantsApplied is the set of grants now in effect on the service for the
// account, to be recorded in the binding metadata. Grants pending revoke are
// still included; the caller removes them from the metadata after RevokeGrants
// succeeds.
GrantsApplied []BindingGrant
// Granted lists the grants newly applied on the service by this call. If the
// caller's metadata transaction is rolled back, these are the grants to
// compensate via RevokeGrants.
Granted []BindingGrant
// PendingRevokes lists grants that are applied on the service but no longer
// desired. The caller executes them via RevokeGrants after its metadata
// transaction commits.
PendingRevokes []BindingGrant
}
GrantApplyResult is the outcome of ApplyGrants. ApplyGrants only executes the additive part of a grant change; revokes are computed but not executed, so a caller can defer them until after its metadata transaction commits (a running app may see extra grants during the operation, but never loses a grant from an operation that is later rolled back).
func ApplyGrantsIncremental ¶
func ApplyGrantsIncremental(bindingMetadata BindingMetadata, supportedGrantTypes []GrantType, reapplyAll bool, apply func(grants []BindingGrant) ([]BindingGrant, error)) (GrantApplyResult, error)
ApplyGrantsIncremental is the ApplyGrants scaffolding for bindings that execute grant changes incrementally (SQL databases): parse the desired grants, diff them against the applied grants, execute only the new ones through apply, and assemble the GrantApplyResult bookkeeping the server's commit/rollback machinery depends on.
apply executes the given grants on the service and returns the grants that were actually processed (a grant may be skipped, e.g. when its target table does not exist yet; it is then retried on a later reapplyAll). Grants no longer desired are never executed here: they are returned in PendingRevokes for the caller to run via RevokeGrants after its metadata transaction commits.
func ApplyGrantsRebuild ¶
func ApplyGrantsRebuild(bindingMetadata BindingMetadata, supportedGrantTypes []GrantType, rebuild func(grantsApplied []BindingGrant) error) (GrantApplyResult, error)
ApplyGrantsRebuild is the ApplyGrants scaffolding for bindings that replace the account's whole permission set atomically (redis ACL rules, mongodb role arrays): the desired state is the union of the applied and desired grants (revokes are deferred), and rebuild replaces the account's permissions with exactly that set.
type LaunchConfig ¶
type LaunchConfig struct {
// ExecPath is the provider executable.
ExecPath string
// Logger receives go-plugin lifecycle logs and the provider's forwarded log
// lines. Nil uses go-plugin's default (stderr).
Logger hclog.Logger
// LogLevel is passed to the provider via OPENRUN_PROVIDER_LOG_LEVEL.
LogLevel string
// SecureConfig, when set, verifies the executable's checksum before launch.
SecureConfig *plugin.SecureConfig
}
LaunchConfig configures launching a provider process.
type Logger ¶
Logger is the logger passed to provider implementations. It mirrors the OpenRun server's logger type (a zerolog wrapper) so binding code written against the server's internal interface ports without changes.
type NameOptions ¶
type NameOptions struct {
// MaxLen rejects generated names longer than this; 0 disables the check.
MaxLen int
// Uppercase upper-cases the generated name (Oracle-style identifiers).
Uppercase bool
// KeepIDPrefix keeps the bnd_ prefix of the binding id instead of
// stripping it (used where the full id fits the identifier budget).
KeepIDPrefix bool
}
NameOptions controls AccountName generation.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider is a running provider process, launched by the OpenRun server. Methods mirror the ServiceBinding interface using SDK types; the server converts to its internal types. Application-level failures are returned as *ProviderError; any other error is a transport failure (the process died or broke protocol) and the caller may respawn the provider and retry.
func LaunchProvider ¶
func LaunchProvider(config LaunchConfig) (*Provider, error)
LaunchProvider starts the provider executable and completes the go-plugin handshake. The returned Provider must be closed with Kill.
func (*Provider) ApplyGrants ¶
func (p *Provider) ApplyGrants(ctx context.Context, account map[string]string, bindingMetadata, derivedFromMetadata BindingMetadata, reapplyAll bool) (GrantApplyResult, error)
func (*Provider) DeleteArtifact ¶
func (*Provider) GenerateAccount ¶
func (*Provider) GetAccountEnv ¶
func (*Provider) InitializeService ¶
func (*Provider) RevokeGrants ¶
func (p *Provider) RevokeGrants(ctx context.Context, account map[string]string, derivedFromMetadata BindingMetadata, revokes, regrants []BindingGrant) error
func (*Provider) RunCommand ¶
type ProviderError ¶
type ProviderError struct {
Message string
}
ProviderError is an application-level error reported by a provider: the provider ran and returned a failure. Transport-level failures (provider crashed, protocol error) are returned as ordinary gRPC errors instead, and may be retried by the server after respawning the provider.
func (*ProviderError) Error ¶
func (e *ProviderError) Error() string
type ServeConfig ¶
type ServeConfig struct {
// Bindings maps each service type served by this provider to its builder.
Bindings map[string]Builder
// TypeInfo optionally describes each service type's grant types and config
// schema, keyed by service type, reported to the server via Describe.
TypeInfo map[string]ServiceTypeInfo
// ProviderVersion is the provider's release version, reported via Describe.
ProviderVersion string
}
ServeConfig configures a binding provider process.
type ServiceBinding ¶
type ServiceBinding interface {
// GetAccountEnv returns the names of the env values included in the
// account info for this binding: the always-present params first, then the
// optional params. This is static info: it must be callable on an
// uninitialized instance, before InitializeService.
GetAccountEnv(ctx context.Context) ([]string, []string, error)
// Initialize the service with the given config. This is called when the service binding is created.
InitializeService(ctx context.Context, logger *Logger, serviceConfig map[string]string, runtime ServiceBindingRuntime) error
// Close the service connection. This is called when the service binding is no longer needed.
CloseService(ctx context.Context) error
// Generate the account based on the binding config. This is called once when the binding is created, after the service is initialized.
// The account and its backing artifacts (role/schema, user/database) are created on the endpoint specified in the service config
// and are persisted immediately. The artifacts that were created are returned in creation order; pre-existing objects that the
// account merely references (like the base binding's schema for a derived binding) must not be included. If creation fails
// partway and already-created artifacts cannot be rolled back internally, they are returned along with the error so the
// caller can clean them up.
GenerateAccount(ctx context.Context, bindingId, bindingPath string, bindingMetadata BindingMetadata,
derivedFromMetadata *BindingMetadata, isStaging bool) (map[string]string, []Artifact, error)
// Delete one artifact previously reported as created by GenerateAccount. The caller only passes back artifacts
// created during the current operation; the implementation must delete only the named artifact.
DeleteArtifact(ctx context.Context, artifact Artifact) error
// Apply the grants to the account. This is called when the binding is created, after the account is generated.
// It can be called again if the grants are changed. Only new grants are executed (and persisted immediately);
// grants that need to be removed are returned in PendingRevokes without being executed, for the caller to run
// via RevokeGrants once its metadata transaction commits.
ApplyGrants(ctx context.Context, account map[string]string,
bindingMetadata, derivedFromMetadata BindingMetadata, reapplyAll bool) (GrantApplyResult, error)
// Revoke the given grants from the account, then re-apply the regrants. Called with the PendingRevokes of an
// earlier ApplyGrants after the caller's metadata transaction commits (regrants = the grants that remain
// desired), or with the Granted list to compensate when the transaction is rolled back (regrants = the grants
// that were applied before the operation). The regrants restore privileges that an overlapping revoke removes
// (e.g. revoking read:t1 while read:* remains would otherwise drop SELECT on t1). Revoking a grant that is not
// currently applied must be harmless.
RevokeGrants(ctx context.Context, account map[string]string,
derivedFromMetadata BindingMetadata, revokes, regrants []BindingGrant) error
// Run a command on the endpoint specified in the service config as the binding account.
RunCommand(ctx context.Context, bindingMetadata BindingMetadata, command string) (map[string]any, error)
}
ServiceBinding is the interface a binding provider implements for each service type it serves. The method contracts match the OpenRun server's internal service binding interface; see the method comments for the semantics the server relies on.
type ServiceBindingRuntime ¶
type ServiceBindingRuntime struct {
// LocalhostBindingHostname is the hostname apps should use to reach a
// service running on the server host (e.g. host.docker.internal when apps
// run in containers). Empty when apps run directly on the host.
LocalhostBindingHostname string
}
ServiceBindingRuntime carries server-side runtime settings a binding may need when connecting to the service.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package bindingtest provides test helpers for binding provider tests.
|
Package bindingtest provides test helpers for binding provider tests. |
|
Package sqlbinding provides helpers for bindings backed by database/sql drivers: service initialization, the RunCommand implementation, and identifier quoting primitives.
|
Package sqlbinding provides helpers for bindings backed by database/sql drivers: service initialization, the RunCommand implementation, and identifier quoting primitives. |