mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Fix listing nodes in scheduler
This commit is contained in:
		@@ -1579,6 +1579,8 @@ func init() {
 | 
				
			|||||||
			switch label {
 | 
								switch label {
 | 
				
			||||||
			case "name":
 | 
								case "name":
 | 
				
			||||||
				return "metadata.name", value, nil
 | 
									return "metadata.name", value, nil
 | 
				
			||||||
 | 
								case "unschedulable":
 | 
				
			||||||
 | 
									return "spec.unschedulable", value, nil
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
									return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1504,6 +1504,8 @@ func init() {
 | 
				
			|||||||
			switch label {
 | 
								switch label {
 | 
				
			||||||
			case "name":
 | 
								case "name":
 | 
				
			||||||
				return "metadata.name", value, nil
 | 
									return "metadata.name", value, nil
 | 
				
			||||||
 | 
								case "unschedulable":
 | 
				
			||||||
 | 
									return "spec.unschedulable", value, nil
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
									return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,8 @@ func init() {
 | 
				
			|||||||
			switch label {
 | 
								switch label {
 | 
				
			||||||
			case "metadata.name":
 | 
								case "metadata.name":
 | 
				
			||||||
				return label, value, nil
 | 
									return label, value, nil
 | 
				
			||||||
 | 
								case "spec.unschedulable":
 | 
				
			||||||
 | 
									return label, value, nil
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
									return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -250,6 +250,7 @@ func (r *Request) RequestURI(uri string) *Request {
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	// A constant that clients can use to refer in a field selector to the object name field.
 | 
						// A constant that clients can use to refer in a field selector to the object name field.
 | 
				
			||||||
	// Will be automatically emitted as the correct name for the API version.
 | 
						// Will be automatically emitted as the correct name for the API version.
 | 
				
			||||||
 | 
						NodeUnschedulable = "spec.unschedulable"
 | 
				
			||||||
	ObjectNameField   = "metadata.name"
 | 
						ObjectNameField   = "metadata.name"
 | 
				
			||||||
	PodHost           = "spec.host"
 | 
						PodHost           = "spec.host"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -295,9 +296,11 @@ var fieldMappings = versionToResourceToFieldMapping{
 | 
				
			|||||||
	"v1beta1": resourceTypeToFieldMapping{
 | 
						"v1beta1": resourceTypeToFieldMapping{
 | 
				
			||||||
		"nodes": clientFieldNameToAPIVersionFieldName{
 | 
							"nodes": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			ObjectNameField:   "name",
 | 
								ObjectNameField:   "name",
 | 
				
			||||||
 | 
								NodeUnschedulable: "unschedulable",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"minions": clientFieldNameToAPIVersionFieldName{
 | 
							"minions": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			ObjectNameField:   "name",
 | 
								ObjectNameField:   "name",
 | 
				
			||||||
 | 
								NodeUnschedulable: "unschedulable",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"pods": clientFieldNameToAPIVersionFieldName{
 | 
							"pods": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			PodHost: "DesiredState.Host",
 | 
								PodHost: "DesiredState.Host",
 | 
				
			||||||
@@ -306,9 +309,11 @@ var fieldMappings = versionToResourceToFieldMapping{
 | 
				
			|||||||
	"v1beta2": resourceTypeToFieldMapping{
 | 
						"v1beta2": resourceTypeToFieldMapping{
 | 
				
			||||||
		"nodes": clientFieldNameToAPIVersionFieldName{
 | 
							"nodes": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			ObjectNameField:   "name",
 | 
								ObjectNameField:   "name",
 | 
				
			||||||
 | 
								NodeUnschedulable: "unschedulable",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"minions": clientFieldNameToAPIVersionFieldName{
 | 
							"minions": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			ObjectNameField:   "name",
 | 
								ObjectNameField:   "name",
 | 
				
			||||||
 | 
								NodeUnschedulable: "unschedulable",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"pods": clientFieldNameToAPIVersionFieldName{
 | 
							"pods": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			PodHost: "DesiredState.Host",
 | 
								PodHost: "DesiredState.Host",
 | 
				
			||||||
@@ -317,9 +322,11 @@ var fieldMappings = versionToResourceToFieldMapping{
 | 
				
			|||||||
	"v1beta3": resourceTypeToFieldMapping{
 | 
						"v1beta3": resourceTypeToFieldMapping{
 | 
				
			||||||
		"nodes": clientFieldNameToAPIVersionFieldName{
 | 
							"nodes": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			ObjectNameField:   "metadata.name",
 | 
								ObjectNameField:   "metadata.name",
 | 
				
			||||||
 | 
								NodeUnschedulable: "spec.unschedulable",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"minions": clientFieldNameToAPIVersionFieldName{
 | 
							"minions": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			ObjectNameField:   "metadata.name",
 | 
								ObjectNameField:   "metadata.name",
 | 
				
			||||||
 | 
								NodeUnschedulable: "spec.unschedulable",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"pods": clientFieldNameToAPIVersionFieldName{
 | 
							"pods": clientFieldNameToAPIVersionFieldName{
 | 
				
			||||||
			PodHost: "spec.host",
 | 
								PodHost: "spec.host",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,6 +108,7 @@ type ResourceGetter interface {
 | 
				
			|||||||
func NodeToSelectableFields(node *api.Node) fields.Set {
 | 
					func NodeToSelectableFields(node *api.Node) fields.Set {
 | 
				
			||||||
	return fields.Set{
 | 
						return fields.Set{
 | 
				
			||||||
		"metadata.name":      node.Name,
 | 
							"metadata.name":      node.Name,
 | 
				
			||||||
 | 
							"spec.unschedulable": fmt.Sprint(node.Spec.Unschedulable),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,6 @@ import (
 | 
				
			|||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
					 | 
				
			||||||
	algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
 | 
						algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
				
			||||||
	"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler"
 | 
						"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler"
 | 
				
			||||||
@@ -226,40 +225,9 @@ func (factory *ConfigFactory) createAssignedPodLW() *cache.ListWatch {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// createMinionLW returns a cache.ListWatch that gets all changes to minions.
 | 
					// createMinionLW returns a cache.ListWatch that gets all changes to minions.
 | 
				
			||||||
func (factory *ConfigFactory) createMinionLW() *cache.ListWatch {
 | 
					func (factory *ConfigFactory) createMinionLW() *cache.ListWatch {
 | 
				
			||||||
	return cache.NewListWatchFromClient(factory.Client, "nodes", api.NamespaceAll, parseSelectorOrDie(""))
 | 
						// TODO: Filter out nodes that doesn't have NodeReady condition.
 | 
				
			||||||
}
 | 
						fields := fields.Set{client.NodeUnschedulable: "false"}.AsSelector()
 | 
				
			||||||
 | 
						return cache.NewListWatchFromClient(factory.Client, "nodes", api.NamespaceAll, fields)
 | 
				
			||||||
// Lists all minions and filter out unhealthy ones, then returns
 | 
					 | 
				
			||||||
// an enumerator for cache.Poller.
 | 
					 | 
				
			||||||
func (factory *ConfigFactory) pollMinions() (cache.Enumerator, error) {
 | 
					 | 
				
			||||||
	allNodes, err := factory.Client.Nodes().List(labels.Everything(), fields.Everything())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	nodes := &api.NodeList{
 | 
					 | 
				
			||||||
		TypeMeta: allNodes.TypeMeta,
 | 
					 | 
				
			||||||
		ListMeta: allNodes.ListMeta,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, node := range allNodes.Items {
 | 
					 | 
				
			||||||
		conditionMap := make(map[api.NodeConditionType]*api.NodeCondition)
 | 
					 | 
				
			||||||
		for i := range node.Status.Conditions {
 | 
					 | 
				
			||||||
			cond := node.Status.Conditions[i]
 | 
					 | 
				
			||||||
			conditionMap[cond.Type] = &cond
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if node.Spec.Unschedulable {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if condition, ok := conditionMap[api.NodeReady]; ok {
 | 
					 | 
				
			||||||
			if condition.Status == api.ConditionTrue {
 | 
					 | 
				
			||||||
				nodes.Items = append(nodes.Items, node)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			// If no condition is set, we get unknown node condition. In such cases,
 | 
					 | 
				
			||||||
			// do not add the node.
 | 
					 | 
				
			||||||
			glog.V(2).Infof("Minion %s is not available. Skipping", node.Name)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return &nodeEnumerator{nodes}, nil
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns a cache.ListWatch that gets all changes to services.
 | 
					// Returns a cache.ListWatch that gets all changes to services.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -131,168 +131,6 @@ func PriorityTwo(pod api.Pod, podLister algorithm.PodLister, minionLister algori
 | 
				
			|||||||
	return []algorithm.HostPriority{}, nil
 | 
						return []algorithm.HostPriority{}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPollMinions(t *testing.T) {
 | 
					 | 
				
			||||||
	table := []struct {
 | 
					 | 
				
			||||||
		minions       []api.Node
 | 
					 | 
				
			||||||
		expectedCount int
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			minions: []api.Node{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "foo"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionTrue},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "fiz"},
 | 
					 | 
				
			||||||
					Spec: api.NodeSpec{
 | 
					 | 
				
			||||||
						Unschedulable: false,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "baz"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionTrue},
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionTrue},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "fuz"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionTrue},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
					Spec: api.NodeSpec{
 | 
					 | 
				
			||||||
						Unschedulable: false,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "buz"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionTrue},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
					Spec: api.NodeSpec{
 | 
					 | 
				
			||||||
						Unschedulable: true,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "foobar"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionFalse},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
					Spec: api.NodeSpec{
 | 
					 | 
				
			||||||
						Unschedulable: false,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			expectedCount: 3,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			minions: []api.Node{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "foo"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionTrue},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "bar"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionFalse},
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			expectedCount: 1,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			minions: []api.Node{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "foo"},
 | 
					 | 
				
			||||||
					Spec: api.NodeSpec{
 | 
					 | 
				
			||||||
						Unschedulable: false,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "bar"},
 | 
					 | 
				
			||||||
					Spec: api.NodeSpec{
 | 
					 | 
				
			||||||
						Unschedulable: true,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			expectedCount: 0,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			minions: []api.Node{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "foo"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{
 | 
					 | 
				
			||||||
							{Type: api.NodeReady, Status: api.ConditionTrue},
 | 
					 | 
				
			||||||
							{Type: "invalidValue", Status: api.ConditionFalse}},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			expectedCount: 1,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			minions: []api.Node{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					ObjectMeta: api.ObjectMeta{Name: "foo"},
 | 
					 | 
				
			||||||
					Status: api.NodeStatus{
 | 
					 | 
				
			||||||
						Conditions: []api.NodeCondition{},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			expectedCount: 0,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, item := range table {
 | 
					 | 
				
			||||||
		ml := &api.NodeList{Items: item.minions}
 | 
					 | 
				
			||||||
		handler := util.FakeHandler{
 | 
					 | 
				
			||||||
			StatusCode:   200,
 | 
					 | 
				
			||||||
			ResponseBody: runtime.EncodeOrDie(latest.Codec, ml),
 | 
					 | 
				
			||||||
			T:            t,
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		mux := http.NewServeMux()
 | 
					 | 
				
			||||||
		// FakeHandler musn't be sent requests other than the one you want to test.
 | 
					 | 
				
			||||||
		resource := "nodes"
 | 
					 | 
				
			||||||
		if api.PreV1Beta3(testapi.Version()) {
 | 
					 | 
				
			||||||
			resource = "minions"
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		mux.Handle(testapi.ResourcePath(resource, api.NamespaceAll, ""), &handler)
 | 
					 | 
				
			||||||
		server := httptest.NewServer(mux)
 | 
					 | 
				
			||||||
		defer server.Close()
 | 
					 | 
				
			||||||
		client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
 | 
					 | 
				
			||||||
		cf := NewConfigFactory(client)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ce, err := cf.pollMinions()
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			t.Errorf("Unexpected error: %v", err)
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		handler.ValidateRequest(t, testapi.ResourcePath(resource, api.NamespaceAll, ""), "GET", nil)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if a := ce.Len(); item.expectedCount != a {
 | 
					 | 
				
			||||||
			t.Errorf("Expected %v, got %v", item.expectedCount, a)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestDefaultErrorFunc(t *testing.T) {
 | 
					func TestDefaultErrorFunc(t *testing.T) {
 | 
				
			||||||
	testPod := &api.Pod{
 | 
						testPod := &api.Pod{
 | 
				
			||||||
		ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
 | 
							ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user