mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #49227 from deads2k/quota-01-tighten
Automatic merge from submit-queue (batch tested with PRs 49107, 47177, 49234, 49224, 49227) tighten quota controller interface While debugging a quota performance problem, I had to chase some references deeper than necessary because the interfaces were overly broad. This tightens them. ```release-note NONE ```
This commit is contained in:
		@@ -68,6 +68,7 @@ go_library(
 | 
				
			|||||||
        "//pkg/quota/install:go_default_library",
 | 
					        "//pkg/quota/install:go_default_library",
 | 
				
			||||||
        "//pkg/serviceaccount:go_default_library",
 | 
					        "//pkg/serviceaccount:go_default_library",
 | 
				
			||||||
        "//pkg/util/configz:go_default_library",
 | 
					        "//pkg/util/configz:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/util/metrics:go_default_library",
 | 
				
			||||||
        "//pkg/version:go_default_library",
 | 
					        "//pkg/version:go_default_library",
 | 
				
			||||||
        "//pkg/volume:go_default_library",
 | 
					        "//pkg/volume:go_default_library",
 | 
				
			||||||
        "//pkg/volume/aws_ebs:go_default_library",
 | 
					        "//pkg/volume/aws_ebs:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@ import (
 | 
				
			|||||||
	persistentvolumecontroller "k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
 | 
						persistentvolumecontroller "k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
						"k8s.io/kubernetes/pkg/features"
 | 
				
			||||||
	quotainstall "k8s.io/kubernetes/pkg/quota/install"
 | 
						quotainstall "k8s.io/kubernetes/pkg/quota/install"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/util/metrics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func startServiceController(ctx ControllerContext) (bool, error) {
 | 
					func startServiceController(ctx ControllerContext) (bool, error) {
 | 
				
			||||||
@@ -230,7 +231,7 @@ func startResourceQuotaController(ctx ControllerContext) (bool, error) {
 | 
				
			|||||||
		api.Kind("ConfigMap"),
 | 
							api.Kind("ConfigMap"),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resourceQuotaControllerOptions := &resourcequotacontroller.ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &resourcequotacontroller.ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:                resourceQuotaControllerClient,
 | 
							QuotaClient:               resourceQuotaControllerClient.Core(),
 | 
				
			||||||
		ResourceQuotaInformer:     ctx.InformerFactory.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer:     ctx.InformerFactory.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:              controller.StaticResyncPeriodFunc(ctx.Options.ResourceQuotaSyncPeriod.Duration),
 | 
							ResyncPeriod:              controller.StaticResyncPeriodFunc(ctx.Options.ResourceQuotaSyncPeriod.Duration),
 | 
				
			||||||
		Registry:                  resourceQuotaRegistry,
 | 
							Registry:                  resourceQuotaRegistry,
 | 
				
			||||||
@@ -238,6 +239,10 @@ func startResourceQuotaController(ctx ControllerContext) (bool, error) {
 | 
				
			|||||||
		ReplenishmentResyncPeriod: ResyncPeriod(&ctx.Options),
 | 
							ReplenishmentResyncPeriod: ResyncPeriod(&ctx.Options),
 | 
				
			||||||
		GroupKindsToReplenish:     groupKindsToReplenish,
 | 
							GroupKindsToReplenish:     groupKindsToReplenish,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if resourceQuotaControllerClient.Core().RESTClient().GetRateLimiter() != nil {
 | 
				
			||||||
 | 
							metrics.RegisterMetricAndTrackRateLimiterUsage("resource_quota_controller", resourceQuotaControllerClient.Core().RESTClient().GetRateLimiter())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go resourcequotacontroller.NewResourceQuotaController(
 | 
						go resourcequotacontroller.NewResourceQuotaController(
 | 
				
			||||||
		resourceQuotaControllerOptions,
 | 
							resourceQuotaControllerOptions,
 | 
				
			||||||
	).Run(int(ctx.Options.ConcurrentResourceQuotaSyncs), ctx.Stop)
 | 
						).Run(int(ctx.Options.ConcurrentResourceQuotaSyncs), ctx.Stop)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,6 @@ go_library(
 | 
				
			|||||||
        "//pkg/controller:go_default_library",
 | 
					        "//pkg/controller:go_default_library",
 | 
				
			||||||
        "//pkg/quota:go_default_library",
 | 
					        "//pkg/quota:go_default_library",
 | 
				
			||||||
        "//pkg/quota/evaluator/core:go_default_library",
 | 
					        "//pkg/quota/evaluator/core:go_default_library",
 | 
				
			||||||
        "//pkg/util/metrics:go_default_library",
 | 
					 | 
				
			||||||
        "//vendor/github.com/golang/glog:go_default_library",
 | 
					        "//vendor/github.com/golang/glog:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
					        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
 | 
					        "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
 | 
				
			||||||
@@ -36,7 +35,7 @@ go_library(
 | 
				
			|||||||
        "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
 | 
					        "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/client-go/informers:go_default_library",
 | 
					        "//vendor/k8s.io/client-go/informers:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/client-go/informers/core/v1:go_default_library",
 | 
					        "//vendor/k8s.io/client-go/informers/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/client-go/kubernetes:go_default_library",
 | 
					        "//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/client-go/listers/core/v1:go_default_library",
 | 
					        "//vendor/k8s.io/client-go/listers/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/client-go/tools/cache:go_default_library",
 | 
					        "//vendor/k8s.io/client-go/tools/cache:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/client-go/util/workqueue:go_default_library",
 | 
					        "//vendor/k8s.io/client-go/util/workqueue:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@ import (
 | 
				
			|||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	coreinformers "k8s.io/client-go/informers/core/v1"
 | 
						coreinformers "k8s.io/client-go/informers/core/v1"
 | 
				
			||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
 | 
				
			||||||
	corelisters "k8s.io/client-go/listers/core/v1"
 | 
						corelisters "k8s.io/client-go/listers/core/v1"
 | 
				
			||||||
	"k8s.io/client-go/tools/cache"
 | 
						"k8s.io/client-go/tools/cache"
 | 
				
			||||||
	"k8s.io/client-go/util/workqueue"
 | 
						"k8s.io/client-go/util/workqueue"
 | 
				
			||||||
@@ -40,13 +40,12 @@ import (
 | 
				
			|||||||
	k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
 | 
						k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/controller"
 | 
						"k8s.io/kubernetes/pkg/controller"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/quota"
 | 
						"k8s.io/kubernetes/pkg/quota"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/metrics"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ResourceQuotaControllerOptions holds options for creating a quota controller
 | 
					// ResourceQuotaControllerOptions holds options for creating a quota controller
 | 
				
			||||||
type ResourceQuotaControllerOptions struct {
 | 
					type ResourceQuotaControllerOptions struct {
 | 
				
			||||||
	// Must have authority to list all quotas, and update quota status
 | 
						// Must have authority to list all quotas, and update quota status
 | 
				
			||||||
	KubeClient clientset.Interface
 | 
						QuotaClient corev1client.ResourceQuotasGetter
 | 
				
			||||||
	// Shared informer for resource quotas
 | 
						// Shared informer for resource quotas
 | 
				
			||||||
	ResourceQuotaInformer coreinformers.ResourceQuotaInformer
 | 
						ResourceQuotaInformer coreinformers.ResourceQuotaInformer
 | 
				
			||||||
	// Controls full recalculation of quota usage
 | 
						// Controls full recalculation of quota usage
 | 
				
			||||||
@@ -65,7 +64,7 @@ type ResourceQuotaControllerOptions struct {
 | 
				
			|||||||
// ResourceQuotaController is responsible for tracking quota usage status in the system
 | 
					// ResourceQuotaController is responsible for tracking quota usage status in the system
 | 
				
			||||||
type ResourceQuotaController struct {
 | 
					type ResourceQuotaController struct {
 | 
				
			||||||
	// Must have authority to list all resources in the system, and update quota status
 | 
						// Must have authority to list all resources in the system, and update quota status
 | 
				
			||||||
	kubeClient clientset.Interface
 | 
						rqClient corev1client.ResourceQuotasGetter
 | 
				
			||||||
	// A lister/getter of resource quota objects
 | 
						// A lister/getter of resource quota objects
 | 
				
			||||||
	rqLister corelisters.ResourceQuotaLister
 | 
						rqLister corelisters.ResourceQuotaLister
 | 
				
			||||||
	// A list of functions that return true when their caches have synced
 | 
						// A list of functions that return true when their caches have synced
 | 
				
			||||||
@@ -87,7 +86,7 @@ type ResourceQuotaController struct {
 | 
				
			|||||||
func NewResourceQuotaController(options *ResourceQuotaControllerOptions) *ResourceQuotaController {
 | 
					func NewResourceQuotaController(options *ResourceQuotaControllerOptions) *ResourceQuotaController {
 | 
				
			||||||
	// build the resource quota controller
 | 
						// build the resource quota controller
 | 
				
			||||||
	rq := &ResourceQuotaController{
 | 
						rq := &ResourceQuotaController{
 | 
				
			||||||
		kubeClient:               options.KubeClient,
 | 
							rqClient:                 options.QuotaClient,
 | 
				
			||||||
		rqLister:                 options.ResourceQuotaInformer.Lister(),
 | 
							rqLister:                 options.ResourceQuotaInformer.Lister(),
 | 
				
			||||||
		informerSyncedFuncs:      []cache.InformerSynced{options.ResourceQuotaInformer.Informer().HasSynced},
 | 
							informerSyncedFuncs:      []cache.InformerSynced{options.ResourceQuotaInformer.Informer().HasSynced},
 | 
				
			||||||
		queue:                    workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "resourcequota_primary"),
 | 
							queue:                    workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "resourcequota_primary"),
 | 
				
			||||||
@@ -96,9 +95,6 @@ func NewResourceQuotaController(options *ResourceQuotaControllerOptions) *Resour
 | 
				
			|||||||
		registry:                 options.Registry,
 | 
							registry:                 options.Registry,
 | 
				
			||||||
		replenishmentControllers: []cache.Controller{},
 | 
							replenishmentControllers: []cache.Controller{},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if options.KubeClient != nil && options.KubeClient.Core().RESTClient().GetRateLimiter() != nil {
 | 
					 | 
				
			||||||
		metrics.RegisterMetricAndTrackRateLimiterUsage("resource_quota_controller", options.KubeClient.Core().RESTClient().GetRateLimiter())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// set the synchronization handler
 | 
						// set the synchronization handler
 | 
				
			||||||
	rq.syncHandler = rq.syncResourceQuotaFromKey
 | 
						rq.syncHandler = rq.syncResourceQuotaFromKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -341,7 +337,7 @@ func (rq *ResourceQuotaController) syncResourceQuota(v1ResourceQuota *v1.Resourc
 | 
				
			|||||||
		if err := k8s_api_v1.Convert_api_ResourceQuota_To_v1_ResourceQuota(&usage, v1Usage, nil); err != nil {
 | 
							if err := k8s_api_v1.Convert_api_ResourceQuota_To_v1_ResourceQuota(&usage, v1Usage, nil); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		_, err = rq.kubeClient.Core().ResourceQuotas(usage.Namespace).UpdateStatus(v1Usage)
 | 
							_, err = rq.rqClient.ResourceQuotas(usage.Namespace).UpdateStatus(v1Usage)
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,7 +109,7 @@ func TestSyncResourceQuota(t *testing.T) {
 | 
				
			|||||||
	kubeClient := fake.NewSimpleClientset(&podList, &resourceQuota)
 | 
						kubeClient := fake.NewSimpleClientset(&podList, &resourceQuota)
 | 
				
			||||||
	informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
						informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
				
			||||||
	resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:            kubeClient,
 | 
							QuotaClient:           kubeClient.Core(),
 | 
				
			||||||
		ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
							ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
				
			||||||
		Registry:              install.NewRegistry(kubeClient, nil),
 | 
							Registry:              install.NewRegistry(kubeClient, nil),
 | 
				
			||||||
@@ -196,7 +196,7 @@ func TestSyncResourceQuotaSpecChange(t *testing.T) {
 | 
				
			|||||||
	kubeClient := fake.NewSimpleClientset(&resourceQuota)
 | 
						kubeClient := fake.NewSimpleClientset(&resourceQuota)
 | 
				
			||||||
	informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
						informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
				
			||||||
	resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:            kubeClient,
 | 
							QuotaClient:           kubeClient.Core(),
 | 
				
			||||||
		ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
							ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
				
			||||||
		Registry:              install.NewRegistry(kubeClient, nil),
 | 
							Registry:              install.NewRegistry(kubeClient, nil),
 | 
				
			||||||
@@ -286,7 +286,7 @@ func TestSyncResourceQuotaSpecHardChange(t *testing.T) {
 | 
				
			|||||||
	kubeClient := fake.NewSimpleClientset(&resourceQuota)
 | 
						kubeClient := fake.NewSimpleClientset(&resourceQuota)
 | 
				
			||||||
	informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
						informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
				
			||||||
	resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:            kubeClient,
 | 
							QuotaClient:           kubeClient.Core(),
 | 
				
			||||||
		ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
							ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
				
			||||||
		Registry:              install.NewRegistry(kubeClient, nil),
 | 
							Registry:              install.NewRegistry(kubeClient, nil),
 | 
				
			||||||
@@ -376,7 +376,7 @@ func TestSyncResourceQuotaNoChange(t *testing.T) {
 | 
				
			|||||||
	kubeClient := fake.NewSimpleClientset(&v1.PodList{}, &resourceQuota)
 | 
						kubeClient := fake.NewSimpleClientset(&v1.PodList{}, &resourceQuota)
 | 
				
			||||||
	informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
						informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
				
			||||||
	resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:            kubeClient,
 | 
							QuotaClient:           kubeClient.Core(),
 | 
				
			||||||
		ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
							ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
				
			||||||
		Registry:              install.NewRegistry(kubeClient, nil),
 | 
							Registry:              install.NewRegistry(kubeClient, nil),
 | 
				
			||||||
@@ -410,7 +410,7 @@ func TestAddQuota(t *testing.T) {
 | 
				
			|||||||
	kubeClient := fake.NewSimpleClientset()
 | 
						kubeClient := fake.NewSimpleClientset()
 | 
				
			||||||
	informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
						informerFactory := informers.NewSharedInformerFactory(kubeClient, controller.NoResyncPeriodFunc())
 | 
				
			||||||
	resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:            kubeClient,
 | 
							QuotaClient:           kubeClient.Core(),
 | 
				
			||||||
		ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer: informerFactory.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
							ResyncPeriod:          controller.NoResyncPeriodFunc,
 | 
				
			||||||
		Registry:              install.NewRegistry(kubeClient, nil),
 | 
							Registry:              install.NewRegistry(kubeClient, nil),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,7 +106,7 @@ func TestQuota(t *testing.T) {
 | 
				
			|||||||
		api.Kind("Pod"),
 | 
							api.Kind("Pod"),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resourceQuotaControllerOptions := &resourcequotacontroller.ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &resourcequotacontroller.ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:                clientset,
 | 
							QuotaClient:               clientset.Core(),
 | 
				
			||||||
		ResourceQuotaInformer:     informers.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer:     informers.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:              controller.NoResyncPeriodFunc,
 | 
							ResyncPeriod:              controller.NoResyncPeriodFunc,
 | 
				
			||||||
		Registry:                  resourceQuotaRegistry,
 | 
							Registry:                  resourceQuotaRegistry,
 | 
				
			||||||
@@ -291,7 +291,7 @@ func TestQuotaLimitedResourceDenial(t *testing.T) {
 | 
				
			|||||||
		api.Kind("Pod"),
 | 
							api.Kind("Pod"),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	resourceQuotaControllerOptions := &resourcequotacontroller.ResourceQuotaControllerOptions{
 | 
						resourceQuotaControllerOptions := &resourcequotacontroller.ResourceQuotaControllerOptions{
 | 
				
			||||||
		KubeClient:                clientset,
 | 
							QuotaClient:               clientset.Core(),
 | 
				
			||||||
		ResourceQuotaInformer:     informers.Core().V1().ResourceQuotas(),
 | 
							ResourceQuotaInformer:     informers.Core().V1().ResourceQuotas(),
 | 
				
			||||||
		ResyncPeriod:              controller.NoResyncPeriodFunc,
 | 
							ResyncPeriod:              controller.NoResyncPeriodFunc,
 | 
				
			||||||
		Registry:                  resourceQuotaRegistry,
 | 
							Registry:                  resourceQuotaRegistry,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user