Manually set GVK in extract, add commentary to extractor

This commit is contained in:
Kevin Delgado 2021-07-08 01:56:58 +00:00
parent 9f4a4d812d
commit dda31bbf2e
6 changed files with 40 additions and 31 deletions

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -23,12 +24,17 @@ import (
"sigs.k8s.io/structured-merge-diff/v4/typed" "sigs.k8s.io/structured-merge-diff/v4/typed"
) )
// This is a small hacky script that tests the extract config against a real cluster
// to demonstrate a bug I'm seeing with the GVKParser where it claims there
// are duplicate GVK entries
// TODO: don't commit this, delete it before merging.
// Any and all functionality from this script should be captured in the appropriate integration test.
func main() { func main() {
fmt.Println("vim-go")
defaultNS := "default" defaultNS := "default"
mydep := "mydep" mydep := "mydep"
mgr := "mymanager" mgr := "mymanager"
kubeconfig := "/usr/local/google/home/kevindelgado/.kube/config" // TODO: make this an arg
kubeconfig := os.Getenv("KUBECONFIG")
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil { if err != nil {

View File

@ -337,12 +337,8 @@ func (s unstructuredJSONScheme) Decode(data []byte, _ *schema.GroupVersionKind,
} }
gvk := obj.GetObjectKind().GroupVersionKind() gvk := obj.GetObjectKind().GroupVersionKind()
//goruntime.Breakpoint()
if len(gvk.Kind) == 0 { if len(gvk.Kind) == 0 {
//goruntime.Breakpoint() return nil, &gvk, runtime.NewMissingKindErr(string(data))
//return nil, &gvk, runtime.NewMissingKindErr(string(data))
fmt.Println("MISSING KIND, ignoring err")
fmt.Printf("string(data) = %+v\n", string(data))
} }
return obj, &gvk, nil return obj, &gvk, nil

View File

@ -75,16 +75,13 @@ func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldMan
if !ok { if !ok {
return fmt.Errorf("unable to convert managed fields for %s to unstructured, expected map, got %T", fieldManager, u) return fmt.Errorf("unable to convert managed fields for %s to unstructured, expected map, got %T", fieldManager, u)
} }
fmt.Printf("u = %+v\n", u)
fmt.Println("---") // set the type meta manually if it doesn't exist to avoid missing kind errors
fmt.Printf("typedObj = %+v\n", typedObj) // when decoding from unstructured JSON
fmt.Println("---") if _, ok := m["kind"]; !ok {
fmt.Printf("object = %+v\n", object) m["kind"] = object.GetObjectKind().GroupVersionKind().Kind
fmt.Println("---") m["apiVersion"] = object.GetObjectKind().GroupVersionKind().GroupVersion().String()
fmt.Printf("m = %+v\n", m) }
fmt.Println("---")
fmt.Printf("applyConfiguration = %+v\n", applyConfiguration)
fmt.Println("---")
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, applyConfiguration); err != nil { if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, applyConfiguration); err != nil {
return fmt.Errorf("error extracting into obj from unstructured: %w", err) return fmt.Errorf("error extracting into obj from unstructured: %w", err)
} }

View File

@ -65,15 +65,12 @@ func NewGVKParser(models proto.Models, preserveUnknownFields bool) (*GvkParser,
panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName)) panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName))
} }
gvkList := parseGroupVersionKind(model) gvkList := parseGroupVersionKind(model)
//fmt.Println("+++")
//fmt.Printf("gvkList = %+v\n", gvkList)
//fmt.Println("+++")
for _, gvk := range gvkList { for _, gvk := range gvkList {
if len(gvk.Kind) > 0 { if len(gvk.Kind) > 0 {
_, ok := parser.gvks[gvk] _, ok := parser.gvks[gvk]
if ok { if ok {
//return nil, fmt.Errorf("duplicate entry for %v", gvk) // TODO: double check why this is failing in real_cluster_script.go
fmt.Printf("duplicate entry for %v\n", gvk) return nil, fmt.Errorf("duplicate entry for %v", gvk)
} }
parser.gvks[gvk] = modelName parser.gvks[gvk] = modelName
} }

View File

@ -10,20 +10,27 @@ import (
"sigs.k8s.io/structured-merge-diff/v4/typed" "sigs.k8s.io/structured-merge-diff/v4/typed"
) )
// UnstructuredExtractor enables extracting the applied configuration state from object for fieldManager into an
// unstructured object type.
type UnstructuredExtractor interface { type UnstructuredExtractor interface {
ExtractUnstructured(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error) ExtractUnstructured(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error)
ExtractUnstructuredStatus(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error) ExtractUnstructuredStatus(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error)
} }
type parserCache interface { // objectTypeCache is a cache of typed.ParseableTypes
parserForGVK(gvk schema.GroupVersionKind) (*typed.ParseableType, error) type objectTypeCache interface {
objectTypeForGVK(gvk schema.GroupVersionKind) (*typed.ParseableType, error)
} }
type nonCachingParserCache struct { // nonCachingObjectTypeCache is a objectTypeCache that does no caching
// (i.e. it downloads the OpenAPISchema every time)
// Useful during the proof-of-concept stage until we agree on a caching solution.
type nonCachingObjectTypeCache struct {
discoveryClient *discovery.DiscoveryClient discoveryClient *discovery.DiscoveryClient
} }
func (c *nonCachingParserCache) parserForGVK(gvk schema.GroupVersionKind) (*typed.ParseableType, error) { // objectTypeForGVK retrieves the typed.ParseableType for a given gvk from the cache
func (c *nonCachingObjectTypeCache) objectTypeForGVK(gvk schema.GroupVersionKind) (*typed.ParseableType, error) {
doc, err := c.discoveryClient.OpenAPISchema() doc, err := c.discoveryClient.OpenAPISchema()
if err != nil { if err != nil {
return nil, err return nil, err
@ -43,31 +50,38 @@ func (c *nonCachingParserCache) parserForGVK(gvk schema.GroupVersionKind) (*type
} }
type extractor struct { type extractor struct {
cache parserCache cache objectTypeCache
} }
// NewUnstructuredExtractor creates the extractor with which you can extract the applied configuration
// for a given manager from an unstructured object.
func NewUnstructuredExtractor(dc *discovery.DiscoveryClient) UnstructuredExtractor { func NewUnstructuredExtractor(dc *discovery.DiscoveryClient) UnstructuredExtractor {
return &extractor{ return &extractor{
cache: &nonCachingParserCache{dc}, cache: &nonCachingObjectTypeCache{dc},
} }
} }
// ExtractUnstructured extracts the applied configuration owned by fiieldManager from an unstructured object.
// Note that the apply configuration itself is also an unstructured object.
func (e *extractor) ExtractUnstructured(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error) { func (e *extractor) ExtractUnstructured(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error) {
return e.extractUnstructured(object, fieldManager, "") return e.extractUnstructured(object, fieldManager, "")
} }
// ExtractUnstructuredStatus is the same as ExtractUnstructured except
// that it extracts the status subresource applied configuration.
// Experimental!
func (e *extractor) ExtractUnstructuredStatus(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error) { func (e *extractor) ExtractUnstructuredStatus(object *unstructured.Unstructured, fieldManager string) (*unstructured.Unstructured, error) {
return e.extractUnstructured(object, fieldManager, "status") return e.extractUnstructured(object, fieldManager, "status")
} }
func (e *extractor) extractUnstructured(object *unstructured.Unstructured, fieldManager string, subresource string) (*unstructured.Unstructured, error) { func (e *extractor) extractUnstructured(object *unstructured.Unstructured, fieldManager string, subresource string) (*unstructured.Unstructured, error) {
gvk := object.GetObjectKind().GroupVersionKind() gvk := object.GetObjectKind().GroupVersionKind()
parser, err := e.cache.parserForGVK(gvk) objectType, err := e.cache.objectTypeForGVK(gvk)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result := &unstructured.Unstructured{} result := &unstructured.Unstructured{}
err = managedfields.ExtractInto(object, *parser, fieldManager, result, subresource) err = managedfields.ExtractInto(object, *objectType, fieldManager, result, subresource)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -269,7 +269,6 @@ func (e TypeReflectCacheEntry) FromUnstructured(sv, dv reflect.Value) error {
if err != nil { if err != nil {
return fmt.Errorf("error encoding %s to json: %v", st.String(), err) return fmt.Errorf("error encoding %s to json: %v", st.String(), err)
} }
// TODO: this is where we're failing
if unmarshaler, ok := e.getJsonUnmarshaler(dv); ok { if unmarshaler, ok := e.getJsonUnmarshaler(dv); ok {
return unmarshaler.UnmarshalJSON(data) return unmarshaler.UnmarshalJSON(data)
} }