...

Source file src/github.com/linkerd/linkerd2/pkg/k8s/resource/resource.go

Documentation: github.com/linkerd/linkerd2/pkg/k8s/resource

     1  package resource
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  
     8  	link "github.com/linkerd/linkerd2/controller/gen/apis/link/v1alpha1"
     9  	policy "github.com/linkerd/linkerd2/controller/gen/apis/policy/v1alpha1"
    10  	profile "github.com/linkerd/linkerd2/controller/gen/apis/serviceprofile/v1alpha2"
    11  	"github.com/linkerd/linkerd2/pkg/k8s"
    12  	log "github.com/sirupsen/logrus"
    13  	admissionRegistration "k8s.io/api/admissionregistration/v1"
    14  	apps "k8s.io/api/apps/v1"
    15  	batch "k8s.io/api/batch/v1"
    16  	core "k8s.io/api/core/v1"
    17  	k8sPolicy "k8s.io/api/policy/v1"
    18  	rbac "k8s.io/api/rbac/v1"
    19  	apiextension "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    20  	kerrors "k8s.io/apimachinery/pkg/api/errors"
    21  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    22  	"k8s.io/apimachinery/pkg/runtime"
    23  	"k8s.io/apimachinery/pkg/runtime/schema"
    24  	apiRegistration "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
    25  	apiregistrationv1client "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1"
    26  	"sigs.k8s.io/yaml"
    27  )
    28  
    29  const (
    30  	yamlSep = "---\n"
    31  )
    32  
    33  // Kubernetes is a parent object used to generalize all k8s types
    34  type Kubernetes struct {
    35  	runtime.TypeMeta
    36  	metav1.ObjectMeta `json:"metadata"`
    37  }
    38  
    39  var prunableNamespaceResources []schema.GroupVersionResource = []schema.GroupVersionResource{
    40  	core.SchemeGroupVersion.WithResource("configmaps"),
    41  	batch.SchemeGroupVersion.WithResource("cronjobs"),
    42  	apps.SchemeGroupVersion.WithResource("daemonsets"),
    43  	apps.SchemeGroupVersion.WithResource("deployments"),
    44  	batch.SchemeGroupVersion.WithResource("jobs"),
    45  	policy.SchemeGroupVersion.WithResource("meshtlsauthentications"),
    46  	policy.SchemeGroupVersion.WithResource("networkauthentications"),
    47  	core.SchemeGroupVersion.WithResource("replicationcontrollers"),
    48  	core.SchemeGroupVersion.WithResource("secrets"),
    49  	core.SchemeGroupVersion.WithResource("services"),
    50  	profile.SchemeGroupVersion.WithResource("serviceprofiles"),
    51  	apps.SchemeGroupVersion.WithResource("statefulsets"),
    52  	rbac.SchemeGroupVersion.WithResource("roles"),
    53  	rbac.SchemeGroupVersion.WithResource("rolebindings"),
    54  	core.SchemeGroupVersion.WithResource("serviceaccounts"),
    55  	k8sPolicy.SchemeGroupVersion.WithResource("poddisruptionbudgets"),
    56  	k8s.ServerGVR,
    57  	k8s.SazGVR,
    58  	k8s.AuthorizationPolicyGVR,
    59  	link.SchemeGroupVersion.WithResource("links"),
    60  	k8s.HTTPRouteGVR,
    61  }
    62  
    63  var prunableClusterResources []schema.GroupVersionResource = []schema.GroupVersionResource{
    64  	rbac.SchemeGroupVersion.WithResource("clusterroles"),
    65  	rbac.SchemeGroupVersion.WithResource("clusterrolebindings"),
    66  	apiRegistration.SchemeGroupVersion.WithResource("apiservices"),
    67  	admissionRegistration.SchemeGroupVersion.WithResource("mutatingwebhookconfigurations"),
    68  	admissionRegistration.SchemeGroupVersion.WithResource("validatingwebhookconfigurations"),
    69  	apiextension.SchemeGroupVersion.WithResource("customresourcedefinitions"),
    70  }
    71  
    72  // New returns a kubernetes resource with the given data
    73  func New(apiVersion, kind, name string) Kubernetes {
    74  	return Kubernetes{
    75  		runtime.TypeMeta{
    76  			APIVersion: apiVersion,
    77  			Kind:       kind,
    78  		},
    79  		metav1.ObjectMeta{
    80  			Name: name,
    81  		},
    82  	}
    83  }
    84  
    85  // NewNamespaced returns a namespace scoped kubernetes resource with the given data
    86  func NewNamespaced(apiVersion, kind, name, namespace string) Kubernetes {
    87  	return Kubernetes{
    88  		runtime.TypeMeta{
    89  			APIVersion: apiVersion,
    90  			Kind:       kind,
    91  		},
    92  		metav1.ObjectMeta{
    93  			Name:      name,
    94  			Namespace: namespace,
    95  		},
    96  	}
    97  }
    98  
    99  // RenderResource renders a kubernetes object as a yaml object
   100  func (r Kubernetes) RenderResource(w io.Writer) error {
   101  	b, err := yaml.Marshal(r)
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	_, err = w.Write(b)
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	_, err = w.Write([]byte(yamlSep))
   112  	return err
   113  }
   114  
   115  // FetchKubernetesResources returns a slice of all cluster scoped kubernetes
   116  // resources which match the given ListOptions.
   117  func FetchKubernetesResources(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   118  
   119  	resources := make([]Kubernetes, 0)
   120  
   121  	clusterRoles, err := fetchClusterRoles(ctx, k, options)
   122  	if err != nil {
   123  		return nil, fmt.Errorf("could not fetch ClusterRole resources: %w", err)
   124  	}
   125  	resources = append(resources, clusterRoles...)
   126  
   127  	clusterRoleBindings, err := fetchClusterRoleBindings(ctx, k, options)
   128  	if err != nil {
   129  		return nil, fmt.Errorf("could not fetch ClusterRoleBinding resources: %w", err)
   130  	}
   131  	resources = append(resources, clusterRoleBindings...)
   132  
   133  	roles, err := fetchRoles(ctx, k, options)
   134  	if err != nil {
   135  		return nil, fmt.Errorf("could not fetch Roles: %w", err)
   136  	}
   137  	resources = append(resources, roles...)
   138  
   139  	roleBindings, err := fetchRoleBindings(ctx, k, options)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("could not fetch RoleBindings: %w", err)
   142  	}
   143  	resources = append(resources, roleBindings...)
   144  
   145  	crds, err := fetchCustomResourceDefinitions(ctx, k, options)
   146  	if err != nil {
   147  		return nil, fmt.Errorf("could not fetch CustomResourceDefinition resources: %w", err)
   148  	}
   149  	resources = append(resources, crds...)
   150  
   151  	apiCRDs, err := fetchAPIRegistrationResources(ctx, k, options)
   152  	if err != nil {
   153  		return nil, fmt.Errorf("could not fetch APIService CRDs: %w", err)
   154  	}
   155  	resources = append(resources, apiCRDs...)
   156  
   157  	mutatinghooks, err := fetchMutatingWebhooksConfiguration(ctx, k, options)
   158  	if err != nil {
   159  		return nil, fmt.Errorf("could not fetch MutatingWebhookConfigurations: %w", err)
   160  	}
   161  	resources = append(resources, mutatinghooks...)
   162  
   163  	validationhooks, err := fetchValidatingWebhooksConfiguration(ctx, k, options)
   164  	if err != nil {
   165  		return nil, fmt.Errorf("could not fetch ValidatingWebhookConfiguration: %w", err)
   166  	}
   167  	resources = append(resources, validationhooks...)
   168  
   169  	namespaces, err := fetchNamespace(ctx, k, options)
   170  	if err != nil {
   171  		return nil, fmt.Errorf("could not fetch Namespace: %w", err)
   172  	}
   173  	resources = append(resources, namespaces...)
   174  
   175  	return resources, nil
   176  }
   177  
   178  func fetchClusterRoles(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   179  	list, err := k.RbacV1().ClusterRoles().List(ctx, options)
   180  	if err != nil {
   181  		return nil, err
   182  	}
   183  
   184  	resources := make([]Kubernetes, len(list.Items))
   185  	for i, item := range list.Items {
   186  		resources[i] = New(rbac.SchemeGroupVersion.String(), "ClusterRole", item.Name)
   187  	}
   188  
   189  	return resources, nil
   190  }
   191  
   192  func fetchClusterRoleBindings(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   193  	list, err := k.RbacV1().ClusterRoleBindings().List(ctx, options)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  
   198  	resources := make([]Kubernetes, len(list.Items))
   199  	for i, item := range list.Items {
   200  		resources[i] = New(rbac.SchemeGroupVersion.String(), "ClusterRoleBinding", item.Name)
   201  	}
   202  
   203  	return resources, nil
   204  }
   205  
   206  func fetchRoles(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   207  	list, err := k.RbacV1().Roles("").List(ctx, options)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	resources := make([]Kubernetes, len(list.Items))
   213  	for i, item := range list.Items {
   214  		r := New(rbac.SchemeGroupVersion.String(), "Role", item.Name)
   215  		r.Namespace = item.Namespace
   216  		resources[i] = r
   217  	}
   218  	return resources, nil
   219  }
   220  
   221  func fetchRoleBindings(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   222  	list, err := k.RbacV1().RoleBindings("").List(ctx, options)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  
   227  	resources := make([]Kubernetes, len(list.Items))
   228  	for i, item := range list.Items {
   229  		r := New(rbac.SchemeGroupVersion.String(), "RoleBinding", item.Name)
   230  		r.Namespace = item.Namespace
   231  		resources[i] = r
   232  	}
   233  	return resources, nil
   234  }
   235  
   236  func fetchCustomResourceDefinitions(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   237  	list, err := k.Apiextensions.ApiextensionsV1().CustomResourceDefinitions().List(ctx, options)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  
   242  	resources := make([]Kubernetes, len(list.Items))
   243  	for i, item := range list.Items {
   244  		resources[i] = New(apiextension.SchemeGroupVersion.String(), "CustomResourceDefinition", item.Name)
   245  	}
   246  
   247  	return resources, nil
   248  }
   249  
   250  func fetchNamespace(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   251  	list, err := k.CoreV1().Namespaces().List(ctx, options)
   252  	if err != nil {
   253  		return nil, err
   254  	}
   255  
   256  	resources := make([]Kubernetes, len(list.Items))
   257  	for i, item := range list.Items {
   258  		r := New(core.SchemeGroupVersion.String(), "Namespace", item.Name)
   259  		r.Namespace = item.Namespace
   260  		resources[i] = r
   261  	}
   262  	return resources, nil
   263  }
   264  
   265  func fetchValidatingWebhooksConfiguration(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   266  	list, err := k.AdmissionregistrationV1().ValidatingWebhookConfigurations().List(ctx, options)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	resources := make([]Kubernetes, len(list.Items))
   272  	for i, item := range list.Items {
   273  		resources[i] = New(admissionRegistration.SchemeGroupVersion.String(), "ValidatingWebhookConfiguration", item.Name)
   274  	}
   275  
   276  	return resources, nil
   277  }
   278  
   279  func fetchMutatingWebhooksConfiguration(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   280  	list, err := k.AdmissionregistrationV1().MutatingWebhookConfigurations().List(ctx, options)
   281  	if err != nil {
   282  		return nil, err
   283  	}
   284  
   285  	resources := make([]Kubernetes, len(list.Items))
   286  	for i, item := range list.Items {
   287  		resources[i] = New(admissionRegistration.SchemeGroupVersion.String(), "MutatingWebhookConfiguration", item.Name)
   288  	}
   289  
   290  	return resources, nil
   291  }
   292  func fetchAPIRegistrationResources(ctx context.Context, k *k8s.KubernetesAPI, options metav1.ListOptions) ([]Kubernetes, error) {
   293  	apiClient, err := apiregistrationv1client.NewForConfig(k.Config)
   294  	if err != nil {
   295  		return nil, err
   296  	}
   297  
   298  	list, err := apiClient.APIServices().List(ctx, options)
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  
   303  	resources := make([]Kubernetes, len(list.Items))
   304  	for i, item := range list.Items {
   305  		resources[i] = New(apiRegistration.SchemeGroupVersion.String(), "APIService", item.Name)
   306  	}
   307  
   308  	return resources, nil
   309  }
   310  
   311  func FetchPrunableResources(ctx context.Context, k *k8s.KubernetesAPI, namespace string, options metav1.ListOptions) ([]Kubernetes, error) {
   312  	resources := []Kubernetes{}
   313  
   314  	for _, gvr := range prunableNamespaceResources {
   315  		items, err := k.DynamicClient.Resource(gvr).Namespace(namespace).List(ctx, options)
   316  		if err != nil {
   317  			if !kerrors.IsNotFound(err) {
   318  				log.Debugf("failed to list resources of type %s", gvr)
   319  			}
   320  			continue
   321  		}
   322  		for _, item := range items.Items {
   323  			resources = append(resources, NewNamespaced(item.GetAPIVersion(), item.GetKind(), item.GetName(), item.GetNamespace()))
   324  		}
   325  	}
   326  
   327  	for _, gvr := range prunableClusterResources {
   328  		items, err := k.DynamicClient.Resource(gvr).List(ctx, options)
   329  		if err != nil {
   330  			log.Debugf("failed to list resources of type %s", gvr)
   331  			continue
   332  		}
   333  		for _, item := range items.Items {
   334  			resources = append(resources, New(item.GetAPIVersion(), item.GetKind(), item.GetName()))
   335  		}
   336  	}
   337  	return resources, nil
   338  }
   339  

View as plain text