client/pkg/dynamic/lib.go

149 lines
4.3 KiB
Go

// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package dynamic
import (
"fmt"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// gvrFromUnstructured takes a unstructured object of CRD type and finds GVR from its spec
func gvrFromUnstructured(u *unstructured.Unstructured) (gvr schema.GroupVersionResource, err error) {
group, err := groupFromUnstructured(u)
if err != nil {
return gvr, err
}
version, err := versionFromUnstructured(u)
if err != nil {
return gvr, err
}
resource, err := resourceFromUnstructured(u)
if err != nil {
return gvr, err
}
return schema.GroupVersionResource{
Group: group,
Version: version,
Resource: resource,
}, nil
}
func groupFromUnstructured(u *unstructured.Unstructured) (string, error) {
content := u.UnstructuredContent()
group, found, err := unstructured.NestedString(content, "spec", "group")
if err != nil || !found {
return "", fmt.Errorf("can't find group for source GVR: %w", err)
}
return group, nil
}
func versionFromUnstructured(u *unstructured.Unstructured) (version string, err error) {
content := u.UnstructuredContent()
versions, found, err := unstructured.NestedSlice(content, "spec", "versions")
if err != nil || !found || len(versions) == 0 {
// fallback to .spec.version
version, found, err = unstructured.NestedString(content, "spec", "version")
if err != nil || !found {
return version, fmt.Errorf("can't find version for source GVR: %w", err)
}
} else {
for _, v := range versions {
if vmap, ok := v.(map[string]interface{}); ok {
// find the version name which is being served
if vmap["served"] == true {
version = vmap["name"].(string)
break
}
}
}
}
// if we could find the version at all
if version == "" {
err = fmt.Errorf("can't find version for source GVR")
}
return version, err
}
func resourceFromUnstructured(u *unstructured.Unstructured) (string, error) {
content := u.UnstructuredContent()
resource, found, err := unstructured.NestedString(content, "spec", "names", "plural")
if err != nil || !found {
return "", fmt.Errorf("can't find resource for source GVR: %w", err)
}
return resource, nil
}
func kindFromUnstructured(u *unstructured.Unstructured) (string, error) {
content := u.UnstructuredContent()
kind, found, err := unstructured.NestedString(content, "spec", "names", "kind")
if !found || err != nil {
return "", fmt.Errorf("can't find source kind from source CRD: %w", err)
}
return kind, nil
}
// TypesFilter for keeping list of sources types to filter upo
type TypesFilter []string
// WithType function for easy filtering on source types
type WithType func(filters *TypesFilter)
// WithTypes for recording the source type filtering function WithType
type WithTypes []WithType
// WithTypeFilter can be used to filter based on source type name
func WithTypeFilter(name string) WithType {
return func(filters *TypesFilter) {
*filters = append(*filters, name)
}
}
// List returns the source type name list recorded via WithTypeFilter
func (types WithTypes) List() []string {
var stypes TypesFilter
for _, f := range types {
f(&stypes)
}
return stypes
}
// UnstructuredCRDFromGVK constructs an unstructured object using the given GVK
func UnstructuredCRDFromGVK(gvk schema.GroupVersionKind) *unstructured.Unstructured {
name := fmt.Sprintf("%ss.%s", strings.ToLower(gvk.Kind), gvk.Group)
plural := fmt.Sprintf("%ss", strings.ToLower(gvk.Kind))
u := &unstructured.Unstructured{}
u.SetUnstructuredContent(map[string]interface{}{
"metadata": map[string]interface{}{
"name": name,
},
"spec": map[string]interface{}{
"group": gvk.Group,
"version": gvk.Version,
"names": map[string]interface{}{
"kind": gvk.Kind,
"plural": plural,
},
},
})
return u
}