Created
June 15, 2020 15:35
-
-
Save isutton/fe3765d98e262b32f89a972bd88c436f to your computer and use it in GitHub Desktop.
New annotation handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package annotations | |
import ( | |
"fmt" | |
"k8s.io/apimachinery/pkg/api/meta" | |
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | |
"k8s.io/apimachinery/pkg/runtime/schema" | |
"k8s.io/client-go/dynamic" | |
) | |
// bindingType encodes the medium the binding should deliver the configuration value. | |
type bindingType string | |
const ( | |
// BindingTypeVolumeMount indicates the binding should happen through a volume mount. | |
BindingTypeVolumeMount bindingType = "volumemount" | |
// BindingTypeEnvVar indicates the binding should happen through environment variables. | |
BindingTypeEnvVar bindingType = "env" | |
) | |
// supportedBindingTypes contains all currently supported binding types. | |
var supportedBindingTypes = map[bindingType]bool{ | |
BindingTypeVolumeMount: true, | |
BindingTypeEnvVar: true, | |
} | |
// dataPath is the path ConfigMap and Secret resources use to scope their data. | |
// | |
// note: it is currently used to provide a pointer to the "data" string, which is the location | |
// ConfigMap and Secret resources keep user data. | |
var dataPath = "data" | |
// result contains data that has been collected by an annotation handler. | |
type result struct { | |
// Data contains the annotation data collected by an annotation handler inside a deep structure | |
// with its root being the value specified in the Path field. | |
Data map[string]interface{} | |
// Type indicates where the Object field should be injected in the application; can be either | |
// "env" or "volumemount". | |
Type bindingType | |
// Path is the nested location the collected data can be found in the Data field. | |
Path string | |
// RawData is... | |
RawData map[string]interface{} | |
} | |
// handler should be implemented by types that want to offer a mechanism to provide binding data to | |
// the system. | |
type handler interface { | |
// Handle returns binding data. | |
Handle() (result, error) | |
} | |
type errHandlerNotFound string | |
func (e errHandlerNotFound) Error() string { | |
return fmt.Sprintf("could not find handler for annotation value %q", string(e)) | |
} | |
func IsErrHandlerNotFound(err error) bool { | |
_, ok := err.(errHandlerNotFound) | |
return ok | |
} | |
// BuildHandler attempts to create an annotation handler for the given annotationKey and | |
// annotationValue. kubeClient is required by some annotation handlers, and an error is returned in | |
// the case it is required by an annotation handler but is not defined. | |
func BuildHandler( | |
kubeClient dynamic.Interface, | |
obj *unstructured.Unstructured, | |
annotationKey string, | |
annotationValue string, | |
restMapper meta.RESTMapper, | |
) (handler, error) { | |
bindingInfo, err := NewBindingInfo(annotationKey, annotationValue) | |
if err != nil { | |
return nil, err | |
} | |
val := bindingInfo.Value | |
switch { | |
case isAttribute(val): | |
return newAttributeHandler(bindingInfo, *obj), nil | |
case isSecret(val): | |
return newSecretHandler(kubeClient, bindingInfo, *obj, restMapper) | |
case isConfigMap(val): | |
return newConfigMapHandler(kubeClient, bindingInfo, *obj, restMapper) | |
case isNewAnnotationSyntax(val): | |
return newServiceBindingAnnotationHandler(val) | |
default: | |
return nil, errHandlerNotFound(val) | |
} | |
} | |
func isNewAnnotationSyntax(s string) bool { | |
_, err := buildPayload(s) | |
return err == nil | |
} | |
type serviceBindingAnnotationHandler struct { | |
payload payload | |
} | |
func (h serviceBindingAnnotationHandler) Handle() (result, error) { | |
panic("yolo") | |
} | |
func newServiceBindingAnnotationHandler( | |
client dynamic.Interface, | |
bi *bindingInfo, | |
resource unstructured.Unstructured, | |
relatedGroupVersionResource schema.GroupVersionResource, | |
inputPathPrefix *string, | |
restMapper meta.RESTMapper, | |
annotationValue string, | |
) (handler, error) { | |
// 1. decompose annotationValue into a type (Path, Type, BindAs, ...) | |
payload, err := buildPayload(annotationValue) | |
if err != nil { | |
return nil, err | |
} | |
dataPath := "data" | |
h, err := NewResourceHandler( | |
client, | |
bi, | |
resource, | |
payload.GetGroupVersionResource(), | |
&dataPath, | |
restMapper, | |
) | |
if err != nil { | |
return nil, err | |
} | |
h.stringValue = payload.stringValue | |
return h, nil | |
} | |
type payload struct { | |
bindAs string | |
typ string | |
stringValue func(interface{}) (string, error) | |
} | |
func (p *payload) GetGroupVersionResource() schema.GroupVersionResource { | |
if p.typ == "ConfigMap" { | |
return schema.GroupVersionResource{ | |
Version: "v1", | |
Resource: "configmaps", | |
} | |
} else if p.typ == "Secret" { | |
return schema.GroupVersionResource{ | |
Version: "v1", | |
Resource: "secrets", | |
} | |
} | |
return schema.GroupVersionResource{} | |
} | |
func buildPayload(s string) (*payload, error) { | |
panic("yolo") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment