mirror of
https://github.com/coredns/coredns.git
synced 2025-11-01 10:43:17 -04:00
plugin/metadata: metadata is just label=value (#1914)
This revert 17d807f0 and re-adds the metadata plugin as a plugin that
just sets a label to a value function.
Add package documentation on how to use the metadata package. Make it
clear that any caching is up to the Func implemented.
There are now - no in tree users. We could add the request metadata by
default under names that copy request.Request, i.e
request/ip - remote IP
request/port - remote port
Variables.go has been deleted.
Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
@@ -1,3 +1,33 @@
|
||||
// Package metadata provides an API that allows plugins to add metadata to the context.
|
||||
// Each metadata is stored under a label that has the form <plugin>/<name>. Each metadata
|
||||
// is returned as a Func. When Func is called the metadata is returned. If Func is expensive to
|
||||
// execute it is its responsibility to provide some form of caching. During the handling of a
|
||||
// query it is expected the metadata stays constant.
|
||||
//
|
||||
// Basic example:
|
||||
//
|
||||
// Implement the Provder interface for a plugin:
|
||||
//
|
||||
// func (p P) Metadata(ctx context.Context, state request.Request) context.Context {
|
||||
// cached := ""
|
||||
// f := func() string {
|
||||
// if cached != "" {
|
||||
// return cached
|
||||
// }
|
||||
// cached = expensiveFunc()
|
||||
// return cached
|
||||
// }
|
||||
// metadata.SetValueFunc(ctx, "test/something", f)
|
||||
// return ctx
|
||||
// }
|
||||
//
|
||||
// Check the metadata from another plugin:
|
||||
//
|
||||
// // ...
|
||||
// valueFunc := metadata.ValueFunc(ctx, "test/something")
|
||||
// value := valueFunc()
|
||||
// // use 'value'
|
||||
//
|
||||
package metadata
|
||||
|
||||
import (
|
||||
@@ -8,40 +38,62 @@ import (
|
||||
|
||||
// Provider interface needs to be implemented by each plugin willing to provide
|
||||
// metadata information for other plugins.
|
||||
// Note: this method should work quickly, because it is called for every request
|
||||
// from the metadata plugin.
|
||||
type Provider interface {
|
||||
// List of variables which are provided by current Provider. Must remain constant.
|
||||
MetadataVarNames() []string
|
||||
// Metadata is expected to return a value with metadata information by the key
|
||||
// from 4th argument. Value can be later retrieved from context by any other plugin.
|
||||
// If value is not available by some reason returned boolean value should be false.
|
||||
Metadata(ctx context.Context, state request.Request, variable string) (interface{}, bool)
|
||||
// Metadata adds metadata to the context and returns a (potentially) new context.
|
||||
// Note: this method should work quickly, because it is called for every request
|
||||
// from the metadata plugin.
|
||||
Metadata(ctx context.Context, state request.Request) context.Context
|
||||
}
|
||||
|
||||
// M is metadata information storage.
|
||||
type M map[string]interface{}
|
||||
// Func is the type of function in the metadata, when called they return the value of the label.
|
||||
type Func func() string
|
||||
|
||||
// FromContext retrieves the metadata from the context.
|
||||
func FromContext(ctx context.Context) (M, bool) {
|
||||
if metadata := ctx.Value(metadataKey{}); metadata != nil {
|
||||
if m, ok := metadata.(M); ok {
|
||||
return m, true
|
||||
// Labels returns all metadata keys stored in the context. These label names should be named
|
||||
// as: plugin/NAME, where NAME is something descriptive.
|
||||
func Labels(ctx context.Context) []string {
|
||||
if metadata := ctx.Value(key{}); metadata != nil {
|
||||
if m, ok := metadata.(md); ok {
|
||||
return keys(m)
|
||||
}
|
||||
}
|
||||
return M{}, false
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns metadata value by key.
|
||||
func (m M) Value(key string) (value interface{}, ok bool) {
|
||||
value, ok = m[key]
|
||||
return value, ok
|
||||
// ValueFunc returns the value function of label. If none can be found nil is returned. Calling the
|
||||
// function returns the value of the label.
|
||||
func ValueFunc(ctx context.Context, label string) Func {
|
||||
if metadata := ctx.Value(key{}); metadata != nil {
|
||||
if m, ok := metadata.(md); ok {
|
||||
return m[label]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetValue sets the metadata value under key.
|
||||
func (m M) SetValue(key string, val interface{}) {
|
||||
m[key] = val
|
||||
// SetValueFunc set the metadata label to the value function. If no metadata can be found this is a noop and
|
||||
// false is returned. Any existing value is overwritten.
|
||||
func SetValueFunc(ctx context.Context, label string, f Func) bool {
|
||||
if metadata := ctx.Value(key{}); metadata != nil {
|
||||
if m, ok := metadata.(md); ok {
|
||||
m[label] = f
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// metadataKey defines the type of key that is used to save metadata into the context.
|
||||
type metadataKey struct{}
|
||||
// md is metadata information storage.
|
||||
type md map[string]Func
|
||||
|
||||
// key defines the type of key that is used to save metadata into the context.
|
||||
type key struct{}
|
||||
|
||||
func keys(m map[string]Func) []string {
|
||||
s := make([]string, len(m))
|
||||
i := 0
|
||||
for k := range m {
|
||||
s[i] = k
|
||||
i++
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user