Skip to content

Instantly share code, notes, and snippets.

@yati-sagade
Created November 2, 2025 20:09
Show Gist options
  • Select an option

  • Save yati-sagade/d792238d20c785120fd10716a372dbaf to your computer and use it in GitHub Desktop.

Select an option

Save yati-sagade/d792238d20c785120fd10716a372dbaf to your computer and use it in GitHub Desktop.
discovery -> fallback to object.metadata field check
package main
import (
"bytes"
"fmt"
"os"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
yamlManifest, err := os.ReadFile(os.Args[1])
if err != nil {
panic(fmt.Sprintf("failed to read file: %v", err))
}
decoder := utilyaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(yamlManifest)), 1024)
decUnstructured := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
for {
var rawObj runtime.RawExtension
if err := decoder.Decode(&rawObj); err != nil {
if err.Error() == "EOF" {
fmt.Println("Finished processing YAML document")
break
}
panic(fmt.Sprintf("failed to decode YAML: %v", err))
}
if len(rawObj.Raw) == 0 {
fmt.Println("Skipping empty document")
continue
}
obj := &unstructured.Unstructured{}
_, err := decodeToUnstructured(rawObj.Raw, obj, decUnstructured)
if err != nil {
panic(fmt.Sprintf("decode error: %v", err))
}
out, err := obj.MarshalJSON()
if err != nil {
panic(fmt.Sprintf("failed to marshal object: %v", err))
}
fmt.Printf("---\n%s\n", string(out))
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
if err != nil {
panic(fmt.Sprintf("error building config: %v", err))
}
supports, err := CheckLabelSupport(obj, config)
if err != nil {
panic(fmt.Sprintf("error checking label support: %v", err))
}
fmt.Printf("%s supports labels: %+v", obj.GetKind(), supports)
fmt.Println("----")
}
}
type supportsLabelsResult struct {
ok bool
source string
}
func CheckLabelSupport(obj *unstructured.Unstructured, config *rest.Config) (supportsLabelsResult, error) {
if ok, err := DiscoverySupportsLabels(obj, config); err == nil {
return supportsLabelsResult{ok: ok, source: "discovery"}, nil
}
if ok, err := LocalSupportsLabels(obj); err == nil {
return supportsLabelsResult{ok: ok, source: "local"}, nil
}
return supportsLabelsResult{}, fmt.Errorf("could not determine label support")
}
func LocalSupportsLabels(obj *unstructured.Unstructured) (bool, error) {
// Check if the object has metadata
if obj.Object["metadata"] != nil {
return true, nil
}
return false, nil
}
func DiscoverySupportsLabels(obj *unstructured.Unstructured, config *rest.Config) (bool, error) {
// Create discovery client
discClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
return false, err
}
// Get GVK from the object
gvk := obj.GroupVersionKind()
// Get API resources for this group/version
resources, err := discClient.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
if err != nil {
return false, err
}
// Find the resource
for _, r := range resources.APIResources {
if r.Kind == gvk.Kind {
// If the resource has metadata, it supports labels
if strings.Contains(r.Name, "/metadata") || strings.Contains(r.Name, "metadata") {
return true, nil
}
return true, nil
}
}
return false, fmt.Errorf("resource kind %s not found", gvk.Kind)
}
func decodeToUnstructured(raw []byte, obj *unstructured.Unstructured, dec runtime.Decoder) (*schema.GroupVersionKind, error) {
out, gvk, err := dec.Decode(raw, nil, obj)
if err != nil {
return nil, err
}
_, ok := out.(*unstructured.Unstructured)
if !ok {
return nil, fmt.Errorf("object is not Unstructured")
}
return gvk, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment