Documentation ¶
Index ¶
- Constants
- Variables
- func HasTemplate(template []byte, startDelim string, checkForEncrypted bool) bool
- func JSONToYAML(j []byte) ([]byte, error)
- func UsesEncryption(template []byte, startDelim string, stopDelim string) bool
- type CacheCleanUpFunc
- type CachingQueryAPI
- type ClusterScopedLookupRestrictedError
- type ClusterScopedObjectIdentifier
- type Config
- type EncryptionConfig
- type ResolveOptions
- type TemplateResolver
- func NewResolver(kubeConfig *rest.Config, config Config) (*TemplateResolver, error)
- func NewResolverWithCaching(ctx context.Context, kubeConfig *rest.Config, config Config) (*TemplateResolver, *source.Channel, error)
- func NewResolverWithDynamicWatcher(dynWatcher client.DynamicWatcher, config Config) (*TemplateResolver, error)
- func (t *TemplateResolver) GetFromCache(gvk schema.GroupVersionKind, namespace string, name string) (*unstructured.Unstructured, error)
- func (t *TemplateResolver) GetWatchCount() uint
- func (t *TemplateResolver) ListWatchedFromCache(watcher client.ObjectIdentifier) ([]unstructured.Unstructured, error)
- func (t *TemplateResolver) ResolveTemplate(tmplRaw []byte, context interface{}, options *ResolveOptions) (TemplateResult, error)
- func (t *TemplateResolver) UncacheWatcher(watcher client.ObjectIdentifier) error
- type TemplateResult
Examples ¶
Constants ¶
const (
IVSize = 16 // Size in bytes
)
Variables ¶
var ( ErrAESKeyNotSet = errors.New("AESKey must be set to use this encryption mode") ErrInvalidAESKey = errors.New("the AES key is invalid") ErrInvalidB64OfEncrypted = errors.New("the encrypted string is invalid base64") ErrIVNotSet = errors.New("initialization vector must be set to use this encryption mode") ErrInvalidIV = errors.New("initialization vector must be 128 bits") ErrInvalidPKCS7Padding = errors.New("invalid PCKS7 padding") ErrMissingAPIResource = errors.New("one or more API resources are not installed on the API server") ErrProtectNotEnabled = errors.New("the protect template function is not enabled in this mode") ErrNewLinesNotAllowed = errors.New("new lines are not allowed in the string passed to the toLiteral function") ErrInvalidContextType = errors.New( "the input context must be a struct, with either string fields or map[string]string fields", ) ErrMissingNamespace = errors.New( "the lookup of a single namespaced resource must have a namespace specified", ) ErrRestrictedNamespace = errors.New("the namespace argument is restricted") ErrInvalidInput = errors.New("the input is invalid") ErrCacheDisabled = client.ErrCacheDisabled ErrNoCacheEntry = client.ErrNoCacheEntry ErrContextTransformerFailed = errors.New("the context transformer failed") )
Functions ¶
func HasTemplate ¶
HasTemplate performs a simple check for the template start delimiter or the "$ocm_encrypted" prefix (checkForEncrypted must be set to true) to indicate if the input byte slice has a template. If the startDelim argument is an empty string, the default start delimiter of "{{" will be used.
func JSONToYAML ¶
JSONToYAML converts JSON to YAML using yaml.v3. This is important since line wrapping is disabled in v3.
Types ¶
type CacheCleanUpFunc ¶
type CacheCleanUpFunc func() error
type CachingQueryAPI ¶
type CachingQueryAPI interface { // Get will add an additional watch and return the watched object. Get( gvk schema.GroupVersionKind, namespace string, name string, ) (*unstructured.Unstructured, error) // List will add an additional list watch and return the watched objects. List( gvk schema.GroupVersionKind, namespace string, selector labels.Selector, ) ([]unstructured.Unstructured, error) }
CachingQueryAPI is a limited query API that will cache results. This is used with ContextTransformers.
type ClusterScopedLookupRestrictedError ¶
type ClusterScopedLookupRestrictedError struct {
// contains filtered or unexported fields
}
func (ClusterScopedLookupRestrictedError) Error ¶
func (e ClusterScopedLookupRestrictedError) Error() string
type Config ¶
type Config struct { AdditionalIndentation uint DisabledFunctions []string StartDelim string StopDelim string MissingAPIResourceCacheTTL time.Duration }
Config is a struct containing configuration for the API.
- AdditionalIndentation sets the number of additional spaces to be added to the input number to the indent method. This is useful in situations when the indentation should be relative to a logical starting point in a YAML file.
- DisabledFunctions is a slice of default template function names that should be disabled.
- StartDelim customizes the start delimiter used to distinguish a template action. This defaults to "{{". If StopDelim is set, this must also be set.
- StopDelim customizes the stop delimiter used to distinguish a template action. This defaults to "}}". If StartDelim is set, this must also be set.
- MissingAPIResourceCacheTTL can be set if you want to temporarily cache an API resource is missing to avoid duplicate API queries when a CRD is missing. By default, this will not be cached. Note that this only affects when caching is enabled.
type EncryptionConfig ¶
type EncryptionConfig struct { AESKey []byte AESKeyFallback []byte DecryptionConcurrency uint8 DecryptionEnabled bool EncryptionEnabled bool InitializationVector []byte }
EncryptionConfig is a struct containing configuration for template encryption/decryption functionality.
- AESKey is an AES key (e.g. AES-256) to use for the "protect" template function and decrypting such values.
- AESKeyFallback is an AES key to try if the decryption fails using AESKey.
- DecryptionConcurrency is the concurrency (i.e. number of Goroutines) limit when decrypting encrypted strings. Not setting this value is the equivalent of setting this to 1, which means no concurrency.
- DecryptionEnabled enables automatic decrypting of encrypted strings. AESKey and InitializationVector must also be set if this is enabled.
- EncryptionEnabled enables the "protect" template function and "fromSecret" returns encrypted content. AESKey and InitializationVector must also be set if this is enabled.
- InitializationVector is the initialization vector (IV) used in the AES-CBC encryption/decryption. Note that it must be equal to the AES block size which is always 128 bits (16 bytes). This value must be random but does not need to be private. Its purpose is to make the same plaintext value, when encrypted with the same AES key, appear unique. When performing decryption, the IV must be the same as it was for the encryption of the data. Note that all values encrypted in the template will use this same IV, which means that duplicate plaintext values that are encrypted will yield the same encrypted value in the template.
type ResolveOptions ¶
type ResolveOptions struct { ContextTransformers []func( queryAPI CachingQueryAPI, context interface{}, ) (transformedContext interface{}, err error) ClusterScopedAllowList []ClusterScopedObjectIdentifier EncryptionConfig DisableAutoCacheCleanUp bool InputIsYAML bool LookupNamespace string Watcher *client.ObjectIdentifier }
ResolveOptions is a struct containing configuration for calling ResolveTemplate.
- ContextTransformers is a list of functions that can modify the input context to ResolveTemplate using the caching query API. This is useful if you want to add information about a Kubernetes object in the context and be notified when the object changes.
- ClusterScopedAllowList is a list of cluster-scoped object identifiers (group, kind, name) which are allowed to be used in "lookup" calls even when LookupNamespace is set. A wildcard value `*` may be used in any or all of the fields. The default behavior when LookupNamespace is set is to deny all cluster-scoped lookups.
- EncryptionConfig is the configuration for template encryption/decryption functionality.
- DisableAutoCacheCleanUp will not clean up stale API watches and cache entries after ResolveTemplate is called. The caller must call the CacheCleanUp function returned from ResolveTemplate when done. This is useful if you are splitting up calls to ResolveTemplate for a single template owner object.
- InputIsYAML can be set to true to indicate that the input to the template is already in YAML format and thus does not need to be converted from JSON to YAML before template processing occurs. This should be set to true when passing raw YAML directly to the template resolver.
- LookupNamespace is the namespace to restrict "lookup" template functions (e.g. fromConfigMap) to. If this is not set (i.e. an empty string), then all namespaces can be used.
- Watcher is the Kubernetes object that includes the templates. This is only used when caching is enabled.
type TemplateResolver ¶
type TemplateResolver struct {
// contains filtered or unexported fields
}
TemplateResolver is the API for processing templates. It's better to use the NewResolver function instead of instantiating this directly so that configuration defaults and validation are applied.
func NewResolver ¶
func NewResolver(kubeConfig *rest.Config, config Config) (*TemplateResolver, error)
NewResolver creates a new TemplateResolver instance, which is the API for processing templates.
- kubeConfig is the rest.Config instance used to create Kubernetes clients for template processing.
- config is the Config instance for configuring optional values for template processing.
func NewResolverWithCaching ¶
func NewResolverWithCaching( ctx context.Context, kubeConfig *rest.Config, config Config, ) ( *TemplateResolver, *source.Channel, error, )
NewResolverWithCaching creates a new caching TemplateResolver instance, which is the API for processing templates.
The caching works by adding watches to the objects and list queries used in the templates. A controller-runtime Channel is also returned to trigger reconciles on the watched object provided in ResolveTemplate when a watched object is added, updated, or removed.
ctx should be a cancelable context that should be canceled when you want the background goroutines involving caching to be stopped.
kubeConfig is the rest.Config instance used to create Kubernetes clients for template processing.
config is the Config instance for configuring optional values for template processing.
func NewResolverWithDynamicWatcher ¶
func NewResolverWithDynamicWatcher(dynWatcher client.DynamicWatcher, config Config) (*TemplateResolver, error)
NewResolverWithDynamicWatcher creates a new caching TemplateResolver instance, using the provided dependency-watcher. The caller is responsible for managing the given DynamicWatcher, including starting and stopping it. The caller must start a query batch on the DynamicWatcher for the "watcher" object before calling ResolveTemplate.
- dynWatcher is an already running DynamicWatcher from kubernetes-dependency-watches.
- config is the Config instance for configuring optional values for template processing.
func (*TemplateResolver) GetFromCache ¶
func (t *TemplateResolver) GetFromCache( gvk schema.GroupVersionKind, namespace string, name string, ) (*unstructured.Unstructured, error)
GetFromCache will return the object from the cache. The ErrNoCacheEntry error is returned if no template function has caused an entry to be cached.
func (*TemplateResolver) GetWatchCount ¶
func (t *TemplateResolver) GetWatchCount() uint
GetWatchCount returns the total number of active API watch requests which can be used for metrics.
func (*TemplateResolver) ListWatchedFromCache ¶
func (t *TemplateResolver) ListWatchedFromCache(watcher client.ObjectIdentifier) ([]unstructured.Unstructured, error)
ListWatchedFromCache will return all watched objects by the watcher in the cache. The ErrNoCacheEntry error is returned if no template function has caused an entry to be cached.
func (*TemplateResolver) ResolveTemplate ¶
func (t *TemplateResolver) ResolveTemplate( tmplRaw []byte, context interface{}, options *ResolveOptions, ) (TemplateResult, error)
ResolveTemplate accepts a map marshaled as JSON or YAML. It also accepts a struct with string fields that will be made available when the template is processed. For example, if the argument is `struct{ClusterName string}{"cluster1"}`, the value `cluster1` would be available with `{{ .ClusterName }}`. This can also be `nil` if no fields should be made available.
ResolveTemplate will process any template strings in the map and return the processed map. The ErrMissingAPIResource is returned when one or more "lookup" calls referenced an API resource which isn't installed on the Kubernetes API server.
The input options contains options for template resolution. The options.Watcher field is an ObjectIdentifier that is used in caching mode and the controller-runtime integration. Set this to nil when not in caching mode. When in caching mode, watches are automatically garbage collected when a new call to ResolveTemplate no longer specifies an object or list query it used to.
This method is only concurrency safe when caching is enabled. When caching is disabled, a local cache of objects is stored just for the ResolveTemplate execution to avoid duplicate API queries. If running this method concurrently with caching disabled, you may get some items from the temporary cache while others will be from API queries.
Example ¶
policyYAML := ` --- apiVersion: policy.open-cluster-management.io/v1 kind: ConfigurationPolicy metadata: name: demo-sampleapp-config namespace: sampleapp spec: remediationAction: enforce namespaceSelector: exclude: - kube-* include: - default object-templates: - complianceType: musthave objectDefinition: kind: ConfigMap apiVersion: v1 metadata: name: demo-sampleapp-config namespace: test data: message: '{{ "VGVtcGxhdGVzIHJvY2sh" | base64dec }}' b64-cluster-name: '{{ .ClusterName | base64enc }}' severity: high ` policyJSON, err := yamlToJSON([]byte(policyYAML)) if err != nil { fmt.Fprintf(os.Stderr, "Failed to convert the policy YAML to JSON: %v\n", err) panic(err) } resolver, err := NewResolver(k8sConfig, Config{}) if err != nil { fmt.Fprintf(os.Stderr, "Failed to instantiate the templatesResolver struct: %v\n", err) panic(err) } templateContext := struct{ ClusterName string }{ClusterName: "cluster0001"} tmplResult, err := resolver.ResolveTemplate(policyJSON, templateContext, nil) policyResolvedJSON := tmplResult.ResolvedJSON if err != nil { fmt.Fprintf(os.Stderr, "Failed to process the policy YAML: %v\n", err) panic(err) } var policyResolved interface{} err = yaml.Unmarshal(policyResolvedJSON, &policyResolved) objTmpls := policyResolved.(map[string]interface{})["spec"].(map[string]interface{})["object-templates"] objDef := objTmpls.([]interface{})[0].(map[string]interface{})["objectDefinition"] data, ok := objDef.(map[string]interface{})["data"].(map[string]interface{}) if !ok { fmt.Fprintf(os.Stderr, "Failed to process the policy YAML: %v\n", err) panic(err) } message, ok := data["message"].(string) if !ok { fmt.Fprintf(os.Stderr, "Failed to process the policy YAML: %v\n", err) panic(err) } b64ClusterName, ok := data["b64-cluster-name"].(string) if !ok { fmt.Fprintf(os.Stderr, "Failed to process the policy YAML: %v\n", err) panic(err) } fmt.Println(message) fmt.Println(b64ClusterName)
Output: Templates rock! Y2x1c3RlcjAwMDE=
func (*TemplateResolver) UncacheWatcher ¶
func (t *TemplateResolver) UncacheWatcher(watcher client.ObjectIdentifier) error
UncacheWatcher will clear the watcher from the cache and remove all associated API watches.
type TemplateResult ¶
type TemplateResult struct { ResolvedJSON []byte CacheCleanUp CacheCleanUpFunc // HasSensitiveData is true if a template references a secret or decrypts an encrypted value. HasSensitiveData bool }