Repository: istio/istio
File: pkg/kube/client.go (Go)

Code before:
	if err != nil {
		return nil, nil, fmt.Errorf("get dynamic client: %v", err)
	}
	return obj, dc, nil
}

func (c *client) DynamicClientFor(g schema.GroupVersionKind, obj *unstructured.Unstructured, namespace string) (dynamic.ResourceInterface, error) {
	gvr, namespaced := c.bestEffortToGVR(g, obj, namespace)

	var dr dynamic.ResourceInterface
	if namespaced {
		ns := ""
		if obj != nil {
			ns = obj.GetNamespace()
		}
		if ns == "" {
			ns = namespace
		} else if namespace != "" && ns != namespace {
			return nil, fmt.Errorf("object %v/%v provided namespace %q but apply called with %q", g, obj.GetName(), ns, namespace)
		}
		if ns == "" {
			ns = c.defaultApplyNamespace
		}
		if ns == "" {
			return nil, fmt.Errorf("apply: no namespace was found")
		}
		// namespaced resources should specify the namespace
		dr = c.dynamic.Resource(gvr).Namespace(ns)
	} else {
		// for cluster-wide resources
		dr = c.dynamic.Resource(gvr)
	}
	return dr, nil
}

func (c *client) bestEffortToGVR(g schema.GroupVersionKind, obj *unstructured.Unstructured, namespace string) (schema.GroupVersionResource, bool) {
	if s, f := collections.All.FindByGroupVersionAliasesKind(config.FromKubernetesGVK(g)); f {
		gvr := s.GroupVersionResource()
		// Might have been an alias, assign back the correct version
		gvr.Version = g.Version
		return gvr, !s.IsClusterScoped()
	}
	if c.mapper != nil {
		// Fallback to dynamic lookup
		mapping, err := c.mapper.RESTMapping(g.GroupKind(), g.Version)
		if err == nil {
			return mapping.Resource, mapping.Scope.Name() == meta.RESTScopeNameNamespace
		}
	}
	// Fallback to guessing
	gvr, _ := meta.UnsafeGuessKindToResource(g)

Review comment (bug):
Previously if we didn't supply any namespace we'd just use "" as the namespace name. Did we then get a rejection from the kube API when we try to make the call? Is it better to preserve the old failure mode rather than introduce a new check?

Code after:
	if err != nil {
		return nil, nil, fmt.Errorf("get dynamic client: %v", err)
	}
	return obj, dc, nil
}

func (c *client) DynamicClientFor(g schema.GroupVersionKind, obj *unstructured.Unstructured, namespace string) (dynamic.ResourceInterface, error) {
	gvr, namespaced := c.bestEffortToGVR(g, obj, namespace)

	var dr dynamic.ResourceInterface
	if namespaced {
		ns := ""
		if obj != nil {
			ns = obj.GetNamespace()
		}
		if ns == "" {
			ns = namespace
		} else if namespace != "" && ns != namespace {
			return nil, fmt.Errorf("object %v/%v provided namespace %q but apply called with %q", g, obj.GetName(), ns, namespace)
		}
		if ns == "" {
			ns = c.defaultApplyNamespace
		}
		// namespaced resources should specify the namespace
		dr = c.dynamic.Resource(gvr).Namespace(ns)
	} else {
		// for cluster-wide resources
		dr = c.dynamic.Resource(gvr)
	}
	return dr, nil
}

func (c *client) bestEffortToGVR(g schema.GroupVersionKind, obj *unstructured.Unstructured, namespace string) (schema.GroupVersionResource, bool) {
	if s, f := collections.All.FindByGroupVersionAliasesKind(config.FromKubernetesGVK(g)); f {
		gvr := s.GroupVersionResource()
		// Might have been an alias, assign back the correct version
		gvr.Version = g.Version
		return gvr, !s.IsClusterScoped()
	}
	if c.mapper != nil {
		// Fallback to dynamic lookup
		mapping, err := c.mapper.RESTMapping(g.GroupKind(), g.Version)
		if err == nil {
			return mapping.Resource, mapping.Scope.Name() == meta.RESTScopeNameNamespace
		}
	}
	// Fallback to guessing
	gvr, _ := meta.UnsafeGuessKindToResource(g)
	namespaced := (obj != nil && obj.GetNamespace() != "") || namespace != ""
	return gvr, namespaced
}