GitOps for k8s
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

namespacer.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package kubernetes
  2. import (
  3. "fmt"
  4. "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
  5. "k8s.io/apimachinery/pkg/runtime/schema"
  6. "k8s.io/client-go/discovery"
  7. "k8s.io/client-go/tools/clientcmd"
  8. kresource "github.com/fluxcd/flux/cluster/kubernetes/resource"
  9. )
  10. // The namespace to presume if something doesn't have one, and we
  11. // haven't been told what to use as a fallback. This is what
  12. // `kubectl` uses when there's no config setting the fallback
  13. // namespace.
  14. const defaultFallbackNamespace = "default"
  15. type namespaceViaDiscovery struct {
  16. fallbackNamespace string
  17. disco discovery.DiscoveryInterface
  18. }
  19. // NewNamespacer creates an implementation of Namespacer
  20. func NewNamespacer(d discovery.DiscoveryInterface) (*namespaceViaDiscovery, error) {
  21. fallback, err := getDefaultNamespace()
  22. if err != nil {
  23. return nil, err
  24. }
  25. return &namespaceViaDiscovery{fallbackNamespace: fallback, disco: d}, nil
  26. }
  27. // getDefaultNamespace returns the fallback namespace used by the
  28. // when a namespaced resource doesn't have one specified. This is
  29. // used when syncing to anticipate the identity of a resource in the
  30. // cluster given the manifest from a file (which may be missing the
  31. // namespace).
  32. // A variable is used for mocking in tests.
  33. var getDefaultNamespace = func() (string, error) {
  34. config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
  35. clientcmd.NewDefaultClientConfigLoadingRules(),
  36. &clientcmd.ConfigOverrides{},
  37. ).RawConfig()
  38. if err != nil {
  39. return "", err
  40. }
  41. cc := config.CurrentContext
  42. if c, ok := config.Contexts[cc]; ok && c.Namespace != "" {
  43. return c.Namespace, nil
  44. }
  45. return defaultFallbackNamespace, nil
  46. }
  47. // effectiveNamespace yields the namespace that would be used for this
  48. // resource were it applied, taking into account the kind of the
  49. // resource, and local configuration.
  50. func (n *namespaceViaDiscovery) EffectiveNamespace(m kresource.KubeManifest, knownScopes ResourceScopes) (string, error) {
  51. namespaced, err := n.lookupNamespaced(m.GroupVersion(), m.GetKind(), knownScopes)
  52. switch {
  53. case err != nil:
  54. return "", err
  55. case namespaced && m.GetNamespace() == "":
  56. return n.fallbackNamespace, nil
  57. case !namespaced:
  58. return "", nil
  59. }
  60. return m.GetNamespace(), nil
  61. }
  62. func (n *namespaceViaDiscovery) lookupNamespaced(groupVersion string, kind string, knownScopes ResourceScopes) (bool, error) {
  63. namespaced, clusterErr := n.lookupNamespacedInCluster(groupVersion, kind)
  64. if clusterErr == nil || knownScopes == nil {
  65. return namespaced, nil
  66. }
  67. // Not found in the cluster, let's try the known scopes
  68. gv, err := schema.ParseGroupVersion(groupVersion)
  69. if err != nil {
  70. return false, clusterErr
  71. }
  72. scope, found := knownScopes[gv.WithKind(kind)]
  73. if !found {
  74. return false, clusterErr
  75. }
  76. return scope == v1beta1.NamespaceScoped, nil
  77. }
  78. func (n *namespaceViaDiscovery) lookupNamespacedInCluster(groupVersion, kind string) (bool, error) {
  79. resourceList, err := n.disco.ServerResourcesForGroupVersion(groupVersion)
  80. if err != nil {
  81. return false, fmt.Errorf("error looking up API resources for %s.%s: %s", kind, groupVersion, err.Error())
  82. }
  83. for _, resource := range resourceList.APIResources {
  84. if resource.Kind == kind {
  85. return resource.Namespaced, nil
  86. }
  87. }
  88. return false, fmt.Errorf("resource not found for API %s, kind %s", groupVersion, kind)
  89. }