mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	optionally ignore preferred terms of existing pods unless incoming pod
has inter-pod affinities
This commit is contained in:
		@@ -389,6 +389,27 @@ profiles:
 | 
				
			|||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// high throughput profile config
 | 
				
			||||||
 | 
						highThroughputProfileConfig := filepath.Join(tmpDir, "high-throughput.yaml")
 | 
				
			||||||
 | 
						if err := os.WriteFile(highThroughputProfileConfig, []byte(fmt.Sprintf(`
 | 
				
			||||||
 | 
					apiVersion: kubescheduler.config.k8s.io/v1
 | 
				
			||||||
 | 
					kind: KubeSchedulerConfiguration
 | 
				
			||||||
 | 
					clientConnection:
 | 
				
			||||||
 | 
					  kubeconfig: '%s'
 | 
				
			||||||
 | 
					profiles:
 | 
				
			||||||
 | 
					- schedulerName: "high-throughput-profile"
 | 
				
			||||||
 | 
					  plugins:
 | 
				
			||||||
 | 
					    preScore:
 | 
				
			||||||
 | 
					      enabled:
 | 
				
			||||||
 | 
					      - name: InterPodAffinity
 | 
				
			||||||
 | 
					  pluginConfig:
 | 
				
			||||||
 | 
					  - name: InterPodAffinity
 | 
				
			||||||
 | 
					    args:
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: true
 | 
				
			||||||
 | 
					`, configKubeconfig)), os.FileMode(0600)); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Insulate this test from picking up in-cluster config when run inside a pod
 | 
						// Insulate this test from picking up in-cluster config when run inside a pod
 | 
				
			||||||
	// We can't assume we have permissions to write to /var/run/secrets/... from a unit test to mock in-cluster config for testing
 | 
						// We can't assume we have permissions to write to /var/run/secrets/... from a unit test to mock in-cluster config for testing
 | 
				
			||||||
	originalHost := os.Getenv("KUBERNETES_SERVICE_HOST")
 | 
						originalHost := os.Getenv("KUBERNETES_SERVICE_HOST")
 | 
				
			||||||
@@ -1525,6 +1546,110 @@ profiles:
 | 
				
			|||||||
			expectedError: `key "leaderElect" already set`,
 | 
								expectedError: `key "leaderElect" already set`,
 | 
				
			||||||
			checkErrFn:    runtime.IsStrictDecodingError,
 | 
								checkErrFn:    runtime.IsStrictDecodingError,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "high throughput profile",
 | 
				
			||||||
 | 
								options: &Options{
 | 
				
			||||||
 | 
									ConfigFile: highThroughputProfileConfig,
 | 
				
			||||||
 | 
									Logs:       logs.NewOptions(),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedUsername: "config",
 | 
				
			||||||
 | 
								expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
 | 
				
			||||||
 | 
									TypeMeta: metav1.TypeMeta{
 | 
				
			||||||
 | 
										APIVersion: v1.SchemeGroupVersion.String(),
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Parallelism: 16,
 | 
				
			||||||
 | 
									DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{
 | 
				
			||||||
 | 
										EnableProfiling:           true,
 | 
				
			||||||
 | 
										EnableContentionProfiling: true,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
 | 
				
			||||||
 | 
										LeaderElect:       true,
 | 
				
			||||||
 | 
										LeaseDuration:     metav1.Duration{Duration: 15 * time.Second},
 | 
				
			||||||
 | 
										RenewDeadline:     metav1.Duration{Duration: 10 * time.Second},
 | 
				
			||||||
 | 
										RetryPeriod:       metav1.Duration{Duration: 2 * time.Second},
 | 
				
			||||||
 | 
										ResourceLock:      "leases",
 | 
				
			||||||
 | 
										ResourceNamespace: "kube-system",
 | 
				
			||||||
 | 
										ResourceName:      "kube-scheduler",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
 | 
				
			||||||
 | 
										Kubeconfig:  configKubeconfig,
 | 
				
			||||||
 | 
										QPS:         50,
 | 
				
			||||||
 | 
										Burst:       100,
 | 
				
			||||||
 | 
										ContentType: "application/vnd.kubernetes.protobuf",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									PercentageOfNodesToScore: defaultPercentageOfNodesToScore,
 | 
				
			||||||
 | 
									PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
 | 
				
			||||||
 | 
									PodMaxBackoffSeconds:     defaultPodMaxBackoffSeconds,
 | 
				
			||||||
 | 
									Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											SchedulerName: "high-throughput-profile",
 | 
				
			||||||
 | 
											Plugins: &kubeschedulerconfig.Plugins{
 | 
				
			||||||
 | 
												QueueSort:  defaults.PluginsV1.QueueSort,
 | 
				
			||||||
 | 
												PreFilter:  defaults.PluginsV1.PreFilter,
 | 
				
			||||||
 | 
												Filter:     defaults.PluginsV1.Filter,
 | 
				
			||||||
 | 
												PostFilter: defaults.PluginsV1.PostFilter,
 | 
				
			||||||
 | 
												PreScore: kubeschedulerconfig.PluginSet{
 | 
				
			||||||
 | 
													Enabled: []kubeschedulerconfig.Plugin{
 | 
				
			||||||
 | 
														{Name: "InterPodAffinity"},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												Score:      defaults.PluginsV1.Score,
 | 
				
			||||||
 | 
												Bind:       defaults.PluginsV1.Bind,
 | 
				
			||||||
 | 
												PreBind:    defaults.PluginsV1.PreBind,
 | 
				
			||||||
 | 
												Reserve:    defaults.PluginsV1.Reserve,
 | 
				
			||||||
 | 
												MultiPoint: defaults.PluginsV1.MultiPoint,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											PluginConfig: []kubeschedulerconfig.PluginConfig{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "InterPodAffinity",
 | 
				
			||||||
 | 
													Args: &kubeschedulerconfig.InterPodAffinityArgs{
 | 
				
			||||||
 | 
														HardPodAffinityWeight:              1,
 | 
				
			||||||
 | 
														IgnorePreferredTermsOfExistingPods: true,
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "DefaultPreemption",
 | 
				
			||||||
 | 
													Args: &kubeschedulerconfig.DefaultPreemptionArgs{
 | 
				
			||||||
 | 
														MinCandidateNodesPercentage: 10,
 | 
				
			||||||
 | 
														MinCandidateNodesAbsolute:   100,
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "NodeAffinity",
 | 
				
			||||||
 | 
													Args: &kubeschedulerconfig.NodeAffinityArgs{},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "NodeResourcesBalancedAllocation",
 | 
				
			||||||
 | 
													Args: &kubeschedulerconfig.NodeResourcesBalancedAllocationArgs{
 | 
				
			||||||
 | 
														Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "NodeResourcesFit",
 | 
				
			||||||
 | 
													Args: &kubeschedulerconfig.NodeResourcesFitArgs{
 | 
				
			||||||
 | 
														ScoringStrategy: &kubeschedulerconfig.ScoringStrategy{
 | 
				
			||||||
 | 
															Type:      kubeschedulerconfig.LeastAllocated,
 | 
				
			||||||
 | 
															Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "PodTopologySpread",
 | 
				
			||||||
 | 
													Args: &kubeschedulerconfig.PodTopologySpreadArgs{
 | 
				
			||||||
 | 
														DefaultingType: kubeschedulerconfig.SystemDefaulting,
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "VolumeBinding",
 | 
				
			||||||
 | 
													Args: &kubeschedulerconfig.VolumeBindingArgs{
 | 
				
			||||||
 | 
														BindTimeoutSeconds: 600,
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tc := range testcases {
 | 
						for _, tc := range testcases {
 | 
				
			||||||
@@ -1550,7 +1675,7 @@ profiles:
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				t.Errorf("unexpected error to create a config: %v", err)
 | 
									t.Errorf("unexpected error creating config: %v", err)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								pkg/generated/openapi/zz_generated.openapi.go
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										27
									
								
								pkg/generated/openapi/zz_generated.openapi.go
									
									
									
										generated
									
									
									
								
							@@ -54133,7 +54133,16 @@ func schema_k8sio_kube_scheduler_config_v1_InterPodAffinityArgs(ref common.Refer
 | 
				
			|||||||
							Format:      "int32",
 | 
												Format:      "int32",
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										"ignorePreferredTermsOfExistingPods": {
 | 
				
			||||||
 | 
											SchemaProps: spec.SchemaProps{
 | 
				
			||||||
 | 
												Description: "IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.",
 | 
				
			||||||
 | 
												Default:     false,
 | 
				
			||||||
 | 
												Type:        []string{"boolean"},
 | 
				
			||||||
 | 
												Format:      "",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
 | 
									Required: []string{"ignorePreferredTermsOfExistingPods"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -55237,7 +55246,16 @@ func schema_k8sio_kube_scheduler_config_v1beta2_InterPodAffinityArgs(ref common.
 | 
				
			|||||||
							Format:      "int32",
 | 
												Format:      "int32",
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										"ignorePreferredTermsOfExistingPods": {
 | 
				
			||||||
 | 
											SchemaProps: spec.SchemaProps{
 | 
				
			||||||
 | 
												Description: "IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.",
 | 
				
			||||||
 | 
												Default:     false,
 | 
				
			||||||
 | 
												Type:        []string{"boolean"},
 | 
				
			||||||
 | 
												Format:      "",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
 | 
									Required: []string{"ignorePreferredTermsOfExistingPods"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -56348,7 +56366,16 @@ func schema_k8sio_kube_scheduler_config_v1beta3_InterPodAffinityArgs(ref common.
 | 
				
			|||||||
							Format:      "int32",
 | 
												Format:      "int32",
 | 
				
			||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										"ignorePreferredTermsOfExistingPods": {
 | 
				
			||||||
 | 
											SchemaProps: spec.SchemaProps{
 | 
				
			||||||
 | 
												Description: "IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.",
 | 
				
			||||||
 | 
												Default:     false,
 | 
				
			||||||
 | 
												Type:        []string{"boolean"},
 | 
				
			||||||
 | 
												Format:      "",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
 | 
									Required: []string{"ignorePreferredTermsOfExistingPods"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1134,6 +1134,71 @@ profiles:
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "ignorePreferredTermsOfExistingPods is enabled",
 | 
				
			||||||
 | 
								data: []byte(`
 | 
				
			||||||
 | 
					apiVersion: kubescheduler.config.k8s.io/v1
 | 
				
			||||||
 | 
					kind: KubeSchedulerConfiguration
 | 
				
			||||||
 | 
					profiles:
 | 
				
			||||||
 | 
					- pluginConfig:
 | 
				
			||||||
 | 
					  - name: InterPodAffinity
 | 
				
			||||||
 | 
					    args:
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: true
 | 
				
			||||||
 | 
					`),
 | 
				
			||||||
 | 
								wantProfiles: []config.KubeSchedulerProfile{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										SchedulerName: "default-scheduler",
 | 
				
			||||||
 | 
										Plugins:       defaults.PluginsV1,
 | 
				
			||||||
 | 
										PluginConfig: []config.PluginConfig{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name: "InterPodAffinity",
 | 
				
			||||||
 | 
												Args: &config.InterPodAffinityArgs{
 | 
				
			||||||
 | 
													HardPodAffinityWeight:              1,
 | 
				
			||||||
 | 
													IgnorePreferredTermsOfExistingPods: true,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name: "DefaultPreemption",
 | 
				
			||||||
 | 
												Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name: "NodeAffinity",
 | 
				
			||||||
 | 
												Args: &config.NodeAffinityArgs{},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name: "NodeResourcesBalancedAllocation",
 | 
				
			||||||
 | 
												Args: &config.NodeResourcesBalancedAllocationArgs{
 | 
				
			||||||
 | 
													Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name: "NodeResourcesFit",
 | 
				
			||||||
 | 
												Args: &config.NodeResourcesFitArgs{
 | 
				
			||||||
 | 
													ScoringStrategy: &config.ScoringStrategy{
 | 
				
			||||||
 | 
														Type: config.LeastAllocated,
 | 
				
			||||||
 | 
														Resources: []config.ResourceSpec{
 | 
				
			||||||
 | 
															{Name: "cpu", Weight: 1},
 | 
				
			||||||
 | 
															{Name: "memory", Weight: 1},
 | 
				
			||||||
 | 
														},
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name: "PodTopologySpread",
 | 
				
			||||||
 | 
												Args: &config.PodTopologySpreadArgs{
 | 
				
			||||||
 | 
													DefaultingType: config.SystemDefaulting,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name: "VolumeBinding",
 | 
				
			||||||
 | 
												Args: &config.VolumeBindingArgs{
 | 
				
			||||||
 | 
													BindTimeoutSeconds: 600,
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	decoder := Codecs.UniversalDecoder()
 | 
						decoder := Codecs.UniversalDecoder()
 | 
				
			||||||
	for _, tt := range testCases {
 | 
						for _, tt := range testCases {
 | 
				
			||||||
@@ -1255,6 +1320,7 @@ profiles:
 | 
				
			|||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
      apiVersion: kubescheduler.config.k8s.io/v1beta2
 | 
					      apiVersion: kubescheduler.config.k8s.io/v1beta2
 | 
				
			||||||
      hardPodAffinityWeight: 5
 | 
					      hardPodAffinityWeight: 5
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: false
 | 
				
			||||||
      kind: InterPodAffinityArgs
 | 
					      kind: InterPodAffinityArgs
 | 
				
			||||||
    name: InterPodAffinity
 | 
					    name: InterPodAffinity
 | 
				
			||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
@@ -1360,6 +1426,7 @@ profiles:
 | 
				
			|||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
      apiVersion: kubescheduler.config.k8s.io/v1beta2
 | 
					      apiVersion: kubescheduler.config.k8s.io/v1beta2
 | 
				
			||||||
      hardPodAffinityWeight: 5
 | 
					      hardPodAffinityWeight: 5
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: false
 | 
				
			||||||
      kind: InterPodAffinityArgs
 | 
					      kind: InterPodAffinityArgs
 | 
				
			||||||
    name: InterPodAffinity
 | 
					    name: InterPodAffinity
 | 
				
			||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
@@ -1475,6 +1542,7 @@ profiles:
 | 
				
			|||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
      apiVersion: kubescheduler.config.k8s.io/v1beta3
 | 
					      apiVersion: kubescheduler.config.k8s.io/v1beta3
 | 
				
			||||||
      hardPodAffinityWeight: 5
 | 
					      hardPodAffinityWeight: 5
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: false
 | 
				
			||||||
      kind: InterPodAffinityArgs
 | 
					      kind: InterPodAffinityArgs
 | 
				
			||||||
    name: InterPodAffinity
 | 
					    name: InterPodAffinity
 | 
				
			||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
@@ -1578,6 +1646,7 @@ profiles:
 | 
				
			|||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
      apiVersion: kubescheduler.config.k8s.io/v1beta3
 | 
					      apiVersion: kubescheduler.config.k8s.io/v1beta3
 | 
				
			||||||
      hardPodAffinityWeight: 5
 | 
					      hardPodAffinityWeight: 5
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: false
 | 
				
			||||||
      kind: InterPodAffinityArgs
 | 
					      kind: InterPodAffinityArgs
 | 
				
			||||||
    name: InterPodAffinity
 | 
					    name: InterPodAffinity
 | 
				
			||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
@@ -1693,6 +1762,7 @@ profiles:
 | 
				
			|||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
      apiVersion: kubescheduler.config.k8s.io/v1
 | 
					      apiVersion: kubescheduler.config.k8s.io/v1
 | 
				
			||||||
      hardPodAffinityWeight: 5
 | 
					      hardPodAffinityWeight: 5
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: false
 | 
				
			||||||
      kind: InterPodAffinityArgs
 | 
					      kind: InterPodAffinityArgs
 | 
				
			||||||
    name: InterPodAffinity
 | 
					    name: InterPodAffinity
 | 
				
			||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
@@ -1796,6 +1866,7 @@ profiles:
 | 
				
			|||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
      apiVersion: kubescheduler.config.k8s.io/v1
 | 
					      apiVersion: kubescheduler.config.k8s.io/v1
 | 
				
			||||||
      hardPodAffinityWeight: 5
 | 
					      hardPodAffinityWeight: 5
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: false
 | 
				
			||||||
      kind: InterPodAffinityArgs
 | 
					      kind: InterPodAffinityArgs
 | 
				
			||||||
    name: InterPodAffinity
 | 
					    name: InterPodAffinity
 | 
				
			||||||
  - args:
 | 
					  - args:
 | 
				
			||||||
@@ -1820,6 +1891,57 @@ profiles:
 | 
				
			|||||||
      foo: bar
 | 
					      foo: bar
 | 
				
			||||||
    name: OutOfTreePlugin
 | 
					    name: OutOfTreePlugin
 | 
				
			||||||
  schedulerName: ""
 | 
					  schedulerName: ""
 | 
				
			||||||
 | 
					`,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name:    "v1 ignorePreferredTermsOfExistingPods is enabled",
 | 
				
			||||||
 | 
								version: v1.SchemeGroupVersion,
 | 
				
			||||||
 | 
								obj: &config.KubeSchedulerConfiguration{
 | 
				
			||||||
 | 
									Parallelism: 8,
 | 
				
			||||||
 | 
									Profiles: []config.KubeSchedulerProfile{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											PluginConfig: []config.PluginConfig{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													Name: "InterPodAffinity",
 | 
				
			||||||
 | 
													Args: &config.InterPodAffinityArgs{
 | 
				
			||||||
 | 
														HardPodAffinityWeight:              5,
 | 
				
			||||||
 | 
														IgnorePreferredTermsOfExistingPods: true,
 | 
				
			||||||
 | 
													},
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								want: `apiVersion: kubescheduler.config.k8s.io/v1
 | 
				
			||||||
 | 
					clientConnection:
 | 
				
			||||||
 | 
					  acceptContentTypes: ""
 | 
				
			||||||
 | 
					  burst: 0
 | 
				
			||||||
 | 
					  contentType: ""
 | 
				
			||||||
 | 
					  kubeconfig: ""
 | 
				
			||||||
 | 
					  qps: 0
 | 
				
			||||||
 | 
					enableContentionProfiling: false
 | 
				
			||||||
 | 
					enableProfiling: false
 | 
				
			||||||
 | 
					kind: KubeSchedulerConfiguration
 | 
				
			||||||
 | 
					leaderElection:
 | 
				
			||||||
 | 
					  leaderElect: false
 | 
				
			||||||
 | 
					  leaseDuration: 0s
 | 
				
			||||||
 | 
					  renewDeadline: 0s
 | 
				
			||||||
 | 
					  resourceLock: ""
 | 
				
			||||||
 | 
					  resourceName: ""
 | 
				
			||||||
 | 
					  resourceNamespace: ""
 | 
				
			||||||
 | 
					  retryPeriod: 0s
 | 
				
			||||||
 | 
					parallelism: 8
 | 
				
			||||||
 | 
					podInitialBackoffSeconds: 0
 | 
				
			||||||
 | 
					podMaxBackoffSeconds: 0
 | 
				
			||||||
 | 
					profiles:
 | 
				
			||||||
 | 
					- pluginConfig:
 | 
				
			||||||
 | 
					  - args:
 | 
				
			||||||
 | 
					      apiVersion: kubescheduler.config.k8s.io/v1
 | 
				
			||||||
 | 
					      hardPodAffinityWeight: 5
 | 
				
			||||||
 | 
					      ignorePreferredTermsOfExistingPods: true
 | 
				
			||||||
 | 
					      kind: InterPodAffinityArgs
 | 
				
			||||||
 | 
					    name: InterPodAffinity
 | 
				
			||||||
 | 
					  schedulerName: ""
 | 
				
			||||||
`,
 | 
					`,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,10 @@ type InterPodAffinityArgs struct {
 | 
				
			|||||||
	// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
						// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
				
			||||||
	// matching hard affinity to the incoming pod.
 | 
						// matching hard affinity to the incoming pod.
 | 
				
			||||||
	HardPodAffinityWeight int32
 | 
						HardPodAffinityWeight int32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity
 | 
				
			||||||
 | 
						// rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.
 | 
				
			||||||
 | 
						IgnorePreferredTermsOfExistingPods bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
					// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -375,6 +375,7 @@ func autoConvert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1.I
 | 
				
			|||||||
	if err := metav1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
						if err := metav1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						out.IgnorePreferredTermsOfExistingPods = in.IgnorePreferredTermsOfExistingPods
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -387,6 +388,7 @@ func autoConvert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(in *conf
 | 
				
			|||||||
	if err := metav1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
						if err := metav1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						out.IgnorePreferredTermsOfExistingPods = in.IgnorePreferredTermsOfExistingPods
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -375,6 +375,7 @@ func autoConvert_v1beta2_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in
 | 
				
			|||||||
	if err := v1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
						if err := v1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						out.IgnorePreferredTermsOfExistingPods = in.IgnorePreferredTermsOfExistingPods
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -387,6 +388,7 @@ func autoConvert_config_InterPodAffinityArgs_To_v1beta2_InterPodAffinityArgs(in
 | 
				
			|||||||
	if err := v1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
						if err := v1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						out.IgnorePreferredTermsOfExistingPods = in.IgnorePreferredTermsOfExistingPods
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -375,6 +375,7 @@ func autoConvert_v1beta3_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in
 | 
				
			|||||||
	if err := v1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
						if err := v1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						out.IgnorePreferredTermsOfExistingPods = in.IgnorePreferredTermsOfExistingPods
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -387,6 +388,7 @@ func autoConvert_config_InterPodAffinityArgs_To_v1beta3_InterPodAffinityArgs(in
 | 
				
			|||||||
	if err := v1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
						if err := v1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						out.IgnorePreferredTermsOfExistingPods = in.IgnorePreferredTermsOfExistingPods
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -142,6 +142,15 @@ func (pl *InterPodAffinity) PreScore(
 | 
				
			|||||||
	hasPreferredAffinityConstraints := affinity != nil && affinity.PodAffinity != nil && len(affinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution) > 0
 | 
						hasPreferredAffinityConstraints := affinity != nil && affinity.PodAffinity != nil && len(affinity.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution) > 0
 | 
				
			||||||
	hasPreferredAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil && len(affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution) > 0
 | 
						hasPreferredAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil && len(affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution) > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Optionally ignore calculating preferences of existing pods' affinity rules
 | 
				
			||||||
 | 
						// if the incoming pod has no inter-pod affinities.
 | 
				
			||||||
 | 
						if pl.args.IgnorePreferredTermsOfExistingPods && !hasPreferredAffinityConstraints && !hasPreferredAntiAffinityConstraints {
 | 
				
			||||||
 | 
							cycleState.Write(preScoreStateKey, &preScoreState{
 | 
				
			||||||
 | 
								topologyScore: make(map[string]map[string]int64),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Unless the pod being scheduled has preferred affinity terms, we only
 | 
						// Unless the pod being scheduled has preferred affinity terms, we only
 | 
				
			||||||
	// need to process nodes hosting pods with affinity.
 | 
						// need to process nodes hosting pods with affinity.
 | 
				
			||||||
	var allNodes []*framework.NodeInfo
 | 
						var allNodes []*framework.NodeInfo
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -369,12 +369,13 @@ func TestPreferredAffinity(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		pod          *v1.Pod
 | 
							pod                                *v1.Pod
 | 
				
			||||||
		pods         []*v1.Pod
 | 
							pods                               []*v1.Pod
 | 
				
			||||||
		nodes        []*v1.Node
 | 
							nodes                              []*v1.Node
 | 
				
			||||||
		expectedList framework.NodeScoreList
 | 
							expectedList                       framework.NodeScoreList
 | 
				
			||||||
		name         string
 | 
							name                               string
 | 
				
			||||||
		wantStatus   *framework.Status
 | 
							ignorePreferredTermsOfExistingPods bool
 | 
				
			||||||
 | 
							wantStatus                         *framework.Status
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "all nodes are same priority as Affinity is nil",
 | 
								name: "all nodes are same priority as Affinity is nil",
 | 
				
			||||||
@@ -736,13 +737,41 @@ func TestPreferredAffinity(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			expectedList: []framework.NodeScore{{Name: "node1", Score: 0}, {Name: "node2", Score: framework.MaxNodeScore}},
 | 
								expectedList: []framework.NodeScore{{Name: "node1", Score: 0}, {Name: "node2", Score: framework.MaxNodeScore}},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Ignore preferred terms of existing pods",
 | 
				
			||||||
 | 
								pod:  &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: metav1.ObjectMeta{Labels: podLabelSecurityS2}},
 | 
				
			||||||
 | 
								pods: []*v1.Pod{
 | 
				
			||||||
 | 
									{Spec: v1.PodSpec{NodeName: "node1", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: metav1.ObjectMeta{Labels: podLabelSecurityS1}},
 | 
				
			||||||
 | 
									{Spec: v1.PodSpec{NodeName: "node2", Affinity: stayWithS2InRegion}, ObjectMeta: metav1.ObjectMeta{Labels: podLabelSecurityS2}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nodes: []*v1.Node{
 | 
				
			||||||
 | 
									{ObjectMeta: metav1.ObjectMeta{Name: "node1", Labels: labelRgChina}},
 | 
				
			||||||
 | 
									{ObjectMeta: metav1.ObjectMeta{Name: "node2", Labels: labelRgIndia}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedList:                       []framework.NodeScore{{Name: "node1", Score: 0}, {Name: "node2", Score: 0}},
 | 
				
			||||||
 | 
								ignorePreferredTermsOfExistingPods: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "Do not ignore preferred terms of existing pods",
 | 
				
			||||||
 | 
								pod:  &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: metav1.ObjectMeta{Labels: podLabelSecurityS2}},
 | 
				
			||||||
 | 
								pods: []*v1.Pod{
 | 
				
			||||||
 | 
									{Spec: v1.PodSpec{NodeName: "node1", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: metav1.ObjectMeta{Labels: podLabelSecurityS1}},
 | 
				
			||||||
 | 
									{Spec: v1.PodSpec{NodeName: "node2", Affinity: stayWithS2InRegion}, ObjectMeta: metav1.ObjectMeta{Labels: podLabelSecurityS2}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nodes: []*v1.Node{
 | 
				
			||||||
 | 
									{ObjectMeta: metav1.ObjectMeta{Name: "node1", Labels: labelRgChina}},
 | 
				
			||||||
 | 
									{ObjectMeta: metav1.ObjectMeta{Name: "node2", Labels: labelRgIndia}},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								expectedList:                       []framework.NodeScore{{Name: "node1", Score: 0}, {Name: "node2", Score: framework.MaxNodeScore}},
 | 
				
			||||||
 | 
								ignorePreferredTermsOfExistingPods: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
		t.Run(test.name, func(t *testing.T) {
 | 
							t.Run(test.name, func(t *testing.T) {
 | 
				
			||||||
			ctx, cancel := context.WithCancel(context.Background())
 | 
								ctx, cancel := context.WithCancel(context.Background())
 | 
				
			||||||
			defer cancel()
 | 
								defer cancel()
 | 
				
			||||||
			state := framework.NewCycleState()
 | 
								state := framework.NewCycleState()
 | 
				
			||||||
			p := plugintesting.SetupPluginWithInformers(ctx, t, New, &config.InterPodAffinityArgs{HardPodAffinityWeight: 1}, cache.NewSnapshot(test.pods, test.nodes), namespaces)
 | 
								p := plugintesting.SetupPluginWithInformers(ctx, t, New, &config.InterPodAffinityArgs{HardPodAffinityWeight: 1, IgnorePreferredTermsOfExistingPods: test.ignorePreferredTermsOfExistingPods}, cache.NewSnapshot(test.pods, test.nodes), namespaces)
 | 
				
			||||||
			status := p.(framework.PreScorePlugin).PreScore(ctx, state, test.pod, test.nodes)
 | 
								status := p.(framework.PreScorePlugin).PreScore(ctx, state, test.pod, test.nodes)
 | 
				
			||||||
			if !status.IsSuccess() {
 | 
								if !status.IsSuccess() {
 | 
				
			||||||
				if !strings.Contains(status.Message(), test.wantStatus.Message()) {
 | 
									if !strings.Contains(status.Message(), test.wantStatus.Message()) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,10 @@ type InterPodAffinityArgs struct {
 | 
				
			|||||||
	// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
						// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
				
			||||||
	// matching hard affinity to the incoming pod.
 | 
						// matching hard affinity to the incoming pod.
 | 
				
			||||||
	HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"`
 | 
						HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity
 | 
				
			||||||
 | 
						// rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.
 | 
				
			||||||
 | 
						IgnorePreferredTermsOfExistingPods bool `json:"ignorePreferredTermsOfExistingPods"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
					// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,10 @@ type InterPodAffinityArgs struct {
 | 
				
			|||||||
	// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
						// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
				
			||||||
	// matching hard affinity to the incoming pod.
 | 
						// matching hard affinity to the incoming pod.
 | 
				
			||||||
	HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"`
 | 
						HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity
 | 
				
			||||||
 | 
						// rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.
 | 
				
			||||||
 | 
						IgnorePreferredTermsOfExistingPods bool `json:"ignorePreferredTermsOfExistingPods"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
					// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,10 @@ type InterPodAffinityArgs struct {
 | 
				
			|||||||
	// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
						// HardPodAffinityWeight is the scoring weight for existing pods with a
 | 
				
			||||||
	// matching hard affinity to the incoming pod.
 | 
						// matching hard affinity to the incoming pod.
 | 
				
			||||||
	HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"`
 | 
						HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// IgnorePreferredTermsOfExistingPods configures the scheduler to ignore existing pods' preferred affinity
 | 
				
			||||||
 | 
						// rules when scoring candidate nodes, unless the incoming pod has inter-pod affinities.
 | 
				
			||||||
 | 
						IgnorePreferredTermsOfExistingPods bool `json:"ignorePreferredTermsOfExistingPods"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
					// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user