Sidecar: Update printPod to show restartable init container information
This commit is contained in:
		@@ -815,9 +815,11 @@ func printPodList(podList *api.PodList, options printers.GenerateOptions) ([]met
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow, error) {
 | 
					func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow, error) {
 | 
				
			||||||
	restarts := 0
 | 
						restarts := 0
 | 
				
			||||||
 | 
						restartableInitContainerRestarts := 0
 | 
				
			||||||
	totalContainers := len(pod.Spec.Containers)
 | 
						totalContainers := len(pod.Spec.Containers)
 | 
				
			||||||
	readyContainers := 0
 | 
						readyContainers := 0
 | 
				
			||||||
	lastRestartDate := metav1.NewTime(time.Time{})
 | 
						lastRestartDate := metav1.NewTime(time.Time{})
 | 
				
			||||||
 | 
						lastRestartableInitContainerRestartDate := metav1.NewTime(time.Time{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reason := string(pod.Status.Phase)
 | 
						reason := string(pod.Status.Phase)
 | 
				
			||||||
	if pod.Status.Reason != "" {
 | 
						if pod.Status.Reason != "" {
 | 
				
			||||||
@@ -842,6 +844,14 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
 | 
				
			|||||||
		row.Conditions = podFailedConditions
 | 
							row.Conditions = podFailedConditions
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						initContainers := make(map[string]*api.Container)
 | 
				
			||||||
 | 
						for i := range pod.Spec.InitContainers {
 | 
				
			||||||
 | 
							initContainers[pod.Spec.InitContainers[i].Name] = &pod.Spec.InitContainers[i]
 | 
				
			||||||
 | 
							if isRestartableInitContainer(&pod.Spec.InitContainers[i]) {
 | 
				
			||||||
 | 
								totalContainers++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initializing := false
 | 
						initializing := false
 | 
				
			||||||
	for i := range pod.Status.InitContainerStatuses {
 | 
						for i := range pod.Status.InitContainerStatuses {
 | 
				
			||||||
		container := pod.Status.InitContainerStatuses[i]
 | 
							container := pod.Status.InitContainerStatuses[i]
 | 
				
			||||||
@@ -852,9 +862,24 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
 | 
				
			|||||||
				lastRestartDate = terminatedDate
 | 
									lastRestartDate = terminatedDate
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if isRestartableInitContainer(initContainers[container.Name]) {
 | 
				
			||||||
 | 
								restartableInitContainerRestarts += int(container.RestartCount)
 | 
				
			||||||
 | 
								if container.LastTerminationState.Terminated != nil {
 | 
				
			||||||
 | 
									terminatedDate := container.LastTerminationState.Terminated.FinishedAt
 | 
				
			||||||
 | 
									if lastRestartableInitContainerRestartDate.Before(&terminatedDate) {
 | 
				
			||||||
 | 
										lastRestartableInitContainerRestartDate = terminatedDate
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		switch {
 | 
							switch {
 | 
				
			||||||
		case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
 | 
							case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
 | 
							case isRestartableInitContainer(initContainers[container.Name]) &&
 | 
				
			||||||
 | 
								container.Started != nil && *container.Started:
 | 
				
			||||||
 | 
								if container.Ready {
 | 
				
			||||||
 | 
									readyContainers++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
		case container.State.Terminated != nil:
 | 
							case container.State.Terminated != nil:
 | 
				
			||||||
			// initialization is failed
 | 
								// initialization is failed
 | 
				
			||||||
			if len(container.State.Terminated.Reason) == 0 {
 | 
								if len(container.State.Terminated.Reason) == 0 {
 | 
				
			||||||
@@ -876,8 +901,10 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		break
 | 
							break
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !initializing {
 | 
					
 | 
				
			||||||
		restarts = 0
 | 
						if !initializing || isPodInitializedConditionTrue(&pod.Status) {
 | 
				
			||||||
 | 
							restarts = restartableInitContainerRestarts
 | 
				
			||||||
 | 
							lastRestartDate = lastRestartableInitContainerRestartDate
 | 
				
			||||||
		hasRunning := false
 | 
							hasRunning := false
 | 
				
			||||||
		for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
 | 
							for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
 | 
				
			||||||
			container := pod.Status.ContainerStatuses[i]
 | 
								container := pod.Status.ContainerStatuses[i]
 | 
				
			||||||
@@ -922,7 +949,7 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	restartsStr := strconv.Itoa(restarts)
 | 
						restartsStr := strconv.Itoa(restarts)
 | 
				
			||||||
	if !lastRestartDate.IsZero() {
 | 
						if restarts != 0 && !lastRestartDate.IsZero() {
 | 
				
			||||||
		restartsStr = fmt.Sprintf("%d (%s ago)", restarts, translateTimestampSince(lastRestartDate))
 | 
							restartsStr = fmt.Sprintf("%d (%s ago)", restarts, translateTimestampSince(lastRestartDate))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2996,3 +3023,22 @@ func (list SortableResourceNames) Swap(i, j int) {
 | 
				
			|||||||
func (list SortableResourceNames) Less(i, j int) bool {
 | 
					func (list SortableResourceNames) Less(i, j int) bool {
 | 
				
			||||||
	return list[i] < list[j]
 | 
						return list[i] < list[j]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isRestartableInitContainer(initContainer *api.Container) bool {
 | 
				
			||||||
 | 
						if initContainer.RestartPolicy == nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return *initContainer.RestartPolicy == api.ContainerRestartPolicyAlways
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isPodInitializedConditionTrue(status *api.PodStatus) bool {
 | 
				
			||||||
 | 
						for _, condition := range status.Conditions {
 | 
				
			||||||
 | 
							if condition.Type != api.PodInitialized {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return condition.Status == api.ConditionTrue
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,8 @@ import (
 | 
				
			|||||||
	utilpointer "k8s.io/utils/pointer"
 | 
						utilpointer "k8s.io/utils/pointer"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var containerRestartPolicyAlways = api.ContainerRestartPolicyAlways
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFormatResourceName(t *testing.T) {
 | 
					func TestFormatResourceName(t *testing.T) {
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		kind schema.GroupKind
 | 
							kind schema.GroupKind
 | 
				
			||||||
@@ -1536,6 +1538,200 @@ func TestPrintPod(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPrintPodWithRestartableInitContainer(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							pod    api.Pod
 | 
				
			||||||
 | 
							expect []metav1.TableRow
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Test pod has 2 restartable init containers, the first one running but not started.
 | 
				
			||||||
 | 
								api.Pod{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "test1"},
 | 
				
			||||||
 | 
									Spec: api.PodSpec{
 | 
				
			||||||
 | 
										InitContainers: []api.Container{
 | 
				
			||||||
 | 
											{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
											{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
										}, Containers: make([]api.Container, 1)},
 | 
				
			||||||
 | 
									Status: api.PodStatus{
 | 
				
			||||||
 | 
										Phase: "Pending",
 | 
				
			||||||
 | 
										InitContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:                 "restartable-init-1",
 | 
				
			||||||
 | 
												Ready:                false,
 | 
				
			||||||
 | 
												RestartCount:         3,
 | 
				
			||||||
 | 
												State:                api.ContainerState{Running: &api.ContainerStateRunning{}},
 | 
				
			||||||
 | 
												Started:              utilpointer.Bool(false),
 | 
				
			||||||
 | 
												LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "restartable-init-2",
 | 
				
			||||||
 | 
												Ready:   false,
 | 
				
			||||||
 | 
												State:   api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
 | 
				
			||||||
 | 
												Started: utilpointer.Bool(false),
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										ContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Ready:        false,
 | 
				
			||||||
 | 
												RestartCount: 0,
 | 
				
			||||||
 | 
												State:        api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Conditions: []api.PodCondition{
 | 
				
			||||||
 | 
											{Type: api.PodInitialized, Status: api.ConditionFalse},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								[]metav1.TableRow{{Cells: []interface{}{"test1", "0/3", "Init:0/2", "3 (10s ago)", "<unknown>"}}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Test pod has 2 restartable init containers, the first one started and the second one running but not started.
 | 
				
			||||||
 | 
								api.Pod{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "test1"},
 | 
				
			||||||
 | 
									Spec: api.PodSpec{
 | 
				
			||||||
 | 
										InitContainers: []api.Container{
 | 
				
			||||||
 | 
											{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
											{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
										}, Containers: make([]api.Container, 1)},
 | 
				
			||||||
 | 
									Status: api.PodStatus{
 | 
				
			||||||
 | 
										Phase: "Pending",
 | 
				
			||||||
 | 
										InitContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:                 "restartable-init-1",
 | 
				
			||||||
 | 
												Ready:                false,
 | 
				
			||||||
 | 
												RestartCount:         3,
 | 
				
			||||||
 | 
												State:                api.ContainerState{Running: &api.ContainerStateRunning{}},
 | 
				
			||||||
 | 
												Started:              utilpointer.Bool(true),
 | 
				
			||||||
 | 
												LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "restartable-init-2",
 | 
				
			||||||
 | 
												Ready:   false,
 | 
				
			||||||
 | 
												State:   api.ContainerState{Running: &api.ContainerStateRunning{}},
 | 
				
			||||||
 | 
												Started: utilpointer.Bool(false),
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										ContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Ready:        false,
 | 
				
			||||||
 | 
												RestartCount: 0,
 | 
				
			||||||
 | 
												State:        api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Conditions: []api.PodCondition{
 | 
				
			||||||
 | 
											{Type: api.PodInitialized, Status: api.ConditionFalse},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								[]metav1.TableRow{{Cells: []interface{}{"test1", "0/3", "Init:1/2", "3 (10s ago)", "<unknown>"}}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Test pod has 2 restartable init containers started and 1 container running
 | 
				
			||||||
 | 
								api.Pod{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "test2"},
 | 
				
			||||||
 | 
									Spec: api.PodSpec{
 | 
				
			||||||
 | 
										InitContainers: []api.Container{
 | 
				
			||||||
 | 
											{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
											{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
										}, Containers: make([]api.Container, 1)},
 | 
				
			||||||
 | 
									Status: api.PodStatus{
 | 
				
			||||||
 | 
										Phase: "Running",
 | 
				
			||||||
 | 
										InitContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:                 "restartable-init-1",
 | 
				
			||||||
 | 
												Ready:                false,
 | 
				
			||||||
 | 
												RestartCount:         3,
 | 
				
			||||||
 | 
												State:                api.ContainerState{Running: &api.ContainerStateRunning{}},
 | 
				
			||||||
 | 
												Started:              utilpointer.Bool(true),
 | 
				
			||||||
 | 
												LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "restartable-init-2",
 | 
				
			||||||
 | 
												Ready:   false,
 | 
				
			||||||
 | 
												State:   api.ContainerState{Running: &api.ContainerStateRunning{}},
 | 
				
			||||||
 | 
												Started: utilpointer.Bool(true),
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										ContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Ready:                true,
 | 
				
			||||||
 | 
												RestartCount:         4,
 | 
				
			||||||
 | 
												State:                api.ContainerState{Running: &api.ContainerStateRunning{}},
 | 
				
			||||||
 | 
												LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * time.Second))}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Conditions: []api.PodCondition{
 | 
				
			||||||
 | 
											{Type: api.PodInitialized, Status: api.ConditionTrue},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								[]metav1.TableRow{{Cells: []interface{}{"test2", "1/3", "Running", "7 (10s ago)", "<unknown>"}}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Test pod has 2 restartable init containers completed with non-zero and 1 container completed
 | 
				
			||||||
 | 
								api.Pod{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "test3"},
 | 
				
			||||||
 | 
									Spec: api.PodSpec{
 | 
				
			||||||
 | 
										InitContainers: []api.Container{
 | 
				
			||||||
 | 
											{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
											{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
 | 
				
			||||||
 | 
										}, Containers: make([]api.Container, 1)},
 | 
				
			||||||
 | 
									Status: api.PodStatus{
 | 
				
			||||||
 | 
										Phase: "Succeeded",
 | 
				
			||||||
 | 
										InitContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:                 "restartable-init-1",
 | 
				
			||||||
 | 
												Ready:                false,
 | 
				
			||||||
 | 
												RestartCount:         3,
 | 
				
			||||||
 | 
												State:                api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Error", ExitCode: 137}},
 | 
				
			||||||
 | 
												Started:              utilpointer.Bool(false),
 | 
				
			||||||
 | 
												LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "restartable-init-2",
 | 
				
			||||||
 | 
												Ready:   false,
 | 
				
			||||||
 | 
												State:   api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Error", ExitCode: 137}},
 | 
				
			||||||
 | 
												Started: utilpointer.Bool(false),
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										ContainerStatuses: []api.ContainerStatus{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Ready:                false,
 | 
				
			||||||
 | 
												RestartCount:         4,
 | 
				
			||||||
 | 
												State:                api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Completed", ExitCode: 0}},
 | 
				
			||||||
 | 
												LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * time.Second))}},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Conditions: []api.PodCondition{
 | 
				
			||||||
 | 
											{Type: api.PodInitialized, Status: api.ConditionTrue},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								[]metav1.TableRow{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Cells: []interface{}{"test3", "0/3", "Completed", "7 (10s ago)", "<unknown>"},
 | 
				
			||||||
 | 
										Conditions: []metav1.TableRowCondition{
 | 
				
			||||||
 | 
											{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "The pod has completed successfully."},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, test := range tests {
 | 
				
			||||||
 | 
							rows, err := printPod(&test.pod, printers.GenerateOptions{})
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for i := range rows {
 | 
				
			||||||
 | 
								rows[i].Object.Object = nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !reflect.DeepEqual(test.expect, rows) {
 | 
				
			||||||
 | 
								t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expect, rows))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPrintPodwide(t *testing.T) {
 | 
					func TestPrintPodwide(t *testing.T) {
 | 
				
			||||||
	condition1 := "condition1"
 | 
						condition1 := "condition1"
 | 
				
			||||||
	condition2 := "condition2"
 | 
						condition2 := "condition2"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user