mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	kubeadm phases add all subcommands
This commit is contained in:
		@@ -23,6 +23,7 @@ import (
 | 
				
			|||||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
				
			||||||
 | 
						cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
				
			||||||
	dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
 | 
						dnsaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns"
 | 
				
			||||||
	proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
 | 
						proxyaddon "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/normalizer"
 | 
						"k8s.io/kubernetes/pkg/util/normalizer"
 | 
				
			||||||
@@ -49,8 +50,14 @@ func NewAddonPhase() workflow.Phase {
 | 
				
			|||||||
	return workflow.Phase{
 | 
						return workflow.Phase{
 | 
				
			||||||
		Name:  "addon",
 | 
							Name:  "addon",
 | 
				
			||||||
		Short: "Installs required addons for passing Conformance tests",
 | 
							Short: "Installs required addons for passing Conformance tests",
 | 
				
			||||||
		InheritFlags: getAddonPhaseFlags("all"),
 | 
							Long:  cmdutil.MacroCommandLongDescription,
 | 
				
			||||||
		Phases: []workflow.Phase{
 | 
							Phases: []workflow.Phase{
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Name:           "all",
 | 
				
			||||||
 | 
									Short:          "Installs all the addons",
 | 
				
			||||||
 | 
									InheritFlags:   getAddonPhaseFlags("all"),
 | 
				
			||||||
 | 
									RunAllSiblings: true,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Name:         "coredns",
 | 
									Name:         "coredns",
 | 
				
			||||||
				Short:        "Installs the CoreDNS addon to a Kubernetes cluster",
 | 
									Short:        "Installs the CoreDNS addon to a Kubernetes cluster",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,8 +70,7 @@ func NewCertsPhase() workflow.Phase {
 | 
				
			|||||||
		Short:  "Certificate generation",
 | 
							Short:  "Certificate generation",
 | 
				
			||||||
		Phases: newCertSubPhases(),
 | 
							Phases: newCertSubPhases(),
 | 
				
			||||||
		Run:    runCerts,
 | 
							Run:    runCerts,
 | 
				
			||||||
		InheritFlags: getCertPhaseFlags("all"),
 | 
							Long:   cmdutil.MacroCommandLongDescription,
 | 
				
			||||||
		LocalFlags:   localFlags(),
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -86,6 +85,17 @@ func localFlags() *pflag.FlagSet {
 | 
				
			|||||||
func newCertSubPhases() []workflow.Phase {
 | 
					func newCertSubPhases() []workflow.Phase {
 | 
				
			||||||
	subPhases := []workflow.Phase{}
 | 
						subPhases := []workflow.Phase{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// All subphase
 | 
				
			||||||
 | 
						allPhase := workflow.Phase{
 | 
				
			||||||
 | 
							Name:           "all",
 | 
				
			||||||
 | 
							Short:          "Generates all certificates",
 | 
				
			||||||
 | 
							InheritFlags:   getCertPhaseFlags("all"),
 | 
				
			||||||
 | 
							RunAllSiblings: true,
 | 
				
			||||||
 | 
							LocalFlags:     localFlags(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						subPhases = append(subPhases, allPhase)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	certTree, _ := certsphase.GetDefaultCertList().AsMap().CertTree()
 | 
						certTree, _ := certsphase.GetDefaultCertList().AsMap().CertTree()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for ca, certList := range certTree {
 | 
						for ca, certList := range certTree {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,9 +19,11 @@ package phases
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
				
			||||||
 | 
						cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
				
			||||||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
						kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/normalizer"
 | 
						"k8s.io/kubernetes/pkg/util/normalizer"
 | 
				
			||||||
@@ -71,14 +73,19 @@ func NewControlPlanePhase() workflow.Phase {
 | 
				
			|||||||
	phase := workflow.Phase{
 | 
						phase := workflow.Phase{
 | 
				
			||||||
		Name:  "control-plane",
 | 
							Name:  "control-plane",
 | 
				
			||||||
		Short: "Generates all static Pod manifest files necessary to establish the control plane",
 | 
							Short: "Generates all static Pod manifest files necessary to establish the control plane",
 | 
				
			||||||
		Example: controlPlaneExample,
 | 
							Long:  cmdutil.MacroCommandLongDescription,
 | 
				
			||||||
		Phases: []workflow.Phase{
 | 
							Phases: []workflow.Phase{
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Name:           "all",
 | 
				
			||||||
 | 
									Short:          "Generates all static Pod manifest files",
 | 
				
			||||||
 | 
									InheritFlags:   getControlPlanePhaseFlags("all"),
 | 
				
			||||||
 | 
									RunAllSiblings: true,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			newControlPlaneSubPhase(kubeadmconstants.KubeAPIServer),
 | 
								newControlPlaneSubPhase(kubeadmconstants.KubeAPIServer),
 | 
				
			||||||
			newControlPlaneSubPhase(kubeadmconstants.KubeControllerManager),
 | 
								newControlPlaneSubPhase(kubeadmconstants.KubeControllerManager),
 | 
				
			||||||
			newControlPlaneSubPhase(kubeadmconstants.KubeScheduler),
 | 
								newControlPlaneSubPhase(kubeadmconstants.KubeScheduler),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Run: runControlPlanePhase,
 | 
							Run: runControlPlanePhase,
 | 
				
			||||||
		InheritFlags: getControlPlanePhaseFlags("all"),
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return phase
 | 
						return phase
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ import (
 | 
				
			|||||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
				
			||||||
 | 
						cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
				
			||||||
	etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
 | 
						etcdphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/etcd"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/normalizer"
 | 
						"k8s.io/kubernetes/pkg/util/normalizer"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -50,11 +51,10 @@ func NewEtcdPhase() workflow.Phase {
 | 
				
			|||||||
	phase := workflow.Phase{
 | 
						phase := workflow.Phase{
 | 
				
			||||||
		Name:  "etcd",
 | 
							Name:  "etcd",
 | 
				
			||||||
		Short: "Generates static Pod manifest file for local etcd.",
 | 
							Short: "Generates static Pod manifest file for local etcd.",
 | 
				
			||||||
		Example: etcdLocalExample,
 | 
							Long:  cmdutil.MacroCommandLongDescription,
 | 
				
			||||||
		Phases: []workflow.Phase{
 | 
							Phases: []workflow.Phase{
 | 
				
			||||||
			newEtcdLocalSubPhase(),
 | 
								newEtcdLocalSubPhase(),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		InheritFlags: getEtcdPhaseFlags(),
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return phase
 | 
						return phase
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ import (
 | 
				
			|||||||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
						kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
 | 
				
			||||||
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
						"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
 | 
				
			||||||
 | 
						cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
 | 
				
			||||||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
						kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
				
			||||||
	kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
 | 
						kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/normalizer"
 | 
						"k8s.io/kubernetes/pkg/util/normalizer"
 | 
				
			||||||
@@ -77,14 +78,20 @@ func NewKubeConfigPhase() workflow.Phase {
 | 
				
			|||||||
	return workflow.Phase{
 | 
						return workflow.Phase{
 | 
				
			||||||
		Name:  "kubeconfig",
 | 
							Name:  "kubeconfig",
 | 
				
			||||||
		Short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file",
 | 
							Short: "Generates all kubeconfig files necessary to establish the control plane and the admin kubeconfig file",
 | 
				
			||||||
 | 
							Long:  cmdutil.MacroCommandLongDescription,
 | 
				
			||||||
		Phases: []workflow.Phase{
 | 
							Phases: []workflow.Phase{
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Name:           "all",
 | 
				
			||||||
 | 
									Short:          "Generates all kubeconfig files",
 | 
				
			||||||
 | 
									InheritFlags:   getKubeConfigPhaseFlags("all"),
 | 
				
			||||||
 | 
									RunAllSiblings: true,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			NewKubeConfigFilePhase(kubeadmconstants.AdminKubeConfigFileName),
 | 
								NewKubeConfigFilePhase(kubeadmconstants.AdminKubeConfigFileName),
 | 
				
			||||||
			NewKubeConfigFilePhase(kubeadmconstants.KubeletKubeConfigFileName),
 | 
								NewKubeConfigFilePhase(kubeadmconstants.KubeletKubeConfigFileName),
 | 
				
			||||||
			NewKubeConfigFilePhase(kubeadmconstants.ControllerManagerKubeConfigFileName),
 | 
								NewKubeConfigFilePhase(kubeadmconstants.ControllerManagerKubeConfigFileName),
 | 
				
			||||||
			NewKubeConfigFilePhase(kubeadmconstants.SchedulerKubeConfigFileName),
 | 
								NewKubeConfigFilePhase(kubeadmconstants.SchedulerKubeConfigFileName),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Run: runKubeConfig,
 | 
							Run: runKubeConfig,
 | 
				
			||||||
		InheritFlags: getKubeConfigPhaseFlags("all"),
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,6 +71,11 @@ func NewUploadConfigPhase() workflow.Phase {
 | 
				
			|||||||
		Short:   "Uploads the kubeadm and kubelet configuration to a ConfigMap",
 | 
							Short:   "Uploads the kubeadm and kubelet configuration to a ConfigMap",
 | 
				
			||||||
		Long:    cmdutil.MacroCommandLongDescription,
 | 
							Long:    cmdutil.MacroCommandLongDescription,
 | 
				
			||||||
		Phases: []workflow.Phase{
 | 
							Phases: []workflow.Phase{
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Name:           "all",
 | 
				
			||||||
 | 
									Short:          "Uploads all configuration to a config map",
 | 
				
			||||||
 | 
									RunAllSiblings: true,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Name:         "kubeadm",
 | 
									Name:         "kubeadm",
 | 
				
			||||||
				Short:        "Uploads the kubeadm ClusterConfiguration to a ConfigMap",
 | 
									Short:        "Uploads the kubeadm ClusterConfiguration to a ConfigMap",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,11 @@ type Phase struct {
 | 
				
			|||||||
	// Phases defines a nested, ordered sequence of phases.
 | 
						// Phases defines a nested, ordered sequence of phases.
 | 
				
			||||||
	Phases []Phase
 | 
						Phases []Phase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RunAllSiblings allows to assign to a phase the responsibility to
 | 
				
			||||||
 | 
						// run all the sibling phases
 | 
				
			||||||
 | 
						// Nb. phase marked as RunAllSiblings can not have Run functions
 | 
				
			||||||
 | 
						RunAllSiblings bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Run defines a function implementing the phase action.
 | 
						// Run defines a function implementing the phase action.
 | 
				
			||||||
	// It is recommended to implent type assertion, e.g. using golang type switch,
 | 
						// It is recommended to implent type assertion, e.g. using golang type switch,
 | 
				
			||||||
	// for validating the RunData type.
 | 
						// for validating the RunData type.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -211,6 +211,12 @@ func (e *Runner) Run() error {
 | 
				
			|||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Errors if phases that are meant to create special subcommands only
 | 
				
			||||||
 | 
							// are wrongly assigned Run Methods
 | 
				
			||||||
 | 
							if p.RunAllSiblings && (p.RunIf != nil || p.Run != nil) {
 | 
				
			||||||
 | 
								return errors.Wrapf(err, "phase marked as RunAllSiblings can not have Run functions %s", p.generatedName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If the phase defines a condition to be checked before executing the phase action.
 | 
							// If the phase defines a condition to be checked before executing the phase action.
 | 
				
			||||||
		if p.RunIf != nil {
 | 
							if p.RunIf != nil {
 | 
				
			||||||
			// Check the condition and returns if the condition isn't satisfied (or fails)
 | 
								// Check the condition and returns if the condition isn't satisfied (or fails)
 | 
				
			||||||
@@ -244,7 +250,7 @@ func (e *Runner) Help(cmdUse string) string {
 | 
				
			|||||||
	// computes the max length of for each phase use line
 | 
						// computes the max length of for each phase use line
 | 
				
			||||||
	maxLength := 0
 | 
						maxLength := 0
 | 
				
			||||||
	e.visitAll(func(p *phaseRunner) error {
 | 
						e.visitAll(func(p *phaseRunner) error {
 | 
				
			||||||
		if !p.Hidden {
 | 
							if !p.Hidden && !p.RunAllSiblings {
 | 
				
			||||||
			length := len(p.use)
 | 
								length := len(p.use)
 | 
				
			||||||
			if maxLength < length {
 | 
								if maxLength < length {
 | 
				
			||||||
				maxLength = length
 | 
									maxLength = length
 | 
				
			||||||
@@ -259,7 +265,7 @@ func (e *Runner) Help(cmdUse string) string {
 | 
				
			|||||||
	line += "```\n"
 | 
						line += "```\n"
 | 
				
			||||||
	offset := 2
 | 
						offset := 2
 | 
				
			||||||
	e.visitAll(func(p *phaseRunner) error {
 | 
						e.visitAll(func(p *phaseRunner) error {
 | 
				
			||||||
		if !p.Hidden {
 | 
							if !p.Hidden && !p.RunAllSiblings {
 | 
				
			||||||
			padding := maxLength - len(p.use) + offset
 | 
								padding := maxLength - len(p.use) + offset
 | 
				
			||||||
			line += strings.Repeat(" ", offset*p.level) // indentation
 | 
								line += strings.Repeat(" ", offset*p.level) // indentation
 | 
				
			||||||
			line += p.use                               // name + aliases
 | 
								line += p.use                               // name + aliases
 | 
				
			||||||
@@ -312,17 +318,31 @@ func (e *Runner) BindToCommand(cmd *cobra.Command) {
 | 
				
			|||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// creates nested phase subcommand
 | 
							// initialize phase selector
 | 
				
			||||||
		var phaseCmd = &cobra.Command{
 | 
							phaseSelector := p.generatedName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// if requested, set the phase to run all the sibling phases
 | 
				
			||||||
 | 
							if p.RunAllSiblings {
 | 
				
			||||||
 | 
								phaseSelector = p.parent.generatedName
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// creates phase subcommand
 | 
				
			||||||
 | 
							phaseCmd := &cobra.Command{
 | 
				
			||||||
			Use:     strings.ToLower(p.Name),
 | 
								Use:     strings.ToLower(p.Name),
 | 
				
			||||||
			Short:   p.Short,
 | 
								Short:   p.Short,
 | 
				
			||||||
			Long:    p.Long,
 | 
								Long:    p.Long,
 | 
				
			||||||
			Example: p.Example,
 | 
								Example: p.Example,
 | 
				
			||||||
			Aliases: p.Aliases,
 | 
								Aliases: p.Aliases,
 | 
				
			||||||
			Run: func(cmd *cobra.Command, args []string) {
 | 
								Run: func(cmd *cobra.Command, args []string) {
 | 
				
			||||||
 | 
									// if the phase has subphases, print the help and exits
 | 
				
			||||||
 | 
									if len(p.Phases) > 0 {
 | 
				
			||||||
 | 
										cmd.Help()
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// overrides the command triggering the Runner using the phaseCmd
 | 
									// overrides the command triggering the Runner using the phaseCmd
 | 
				
			||||||
				e.runCmd = cmd
 | 
									e.runCmd = cmd
 | 
				
			||||||
				e.Options.FilterPhases = []string{p.generatedName}
 | 
									e.Options.FilterPhases = []string{phaseSelector}
 | 
				
			||||||
				if err := e.Run(); err != nil {
 | 
									if err := e.Run(); err != nil {
 | 
				
			||||||
					fmt.Fprintln(os.Stderr, err)
 | 
										fmt.Fprintln(os.Stderr, err)
 | 
				
			||||||
					os.Exit(1)
 | 
										os.Exit(1)
 | 
				
			||||||
@@ -405,6 +425,12 @@ func (e *Runner) prepareForExecution() {
 | 
				
			|||||||
	e.phaseRunners = []*phaseRunner{}
 | 
						e.phaseRunners = []*phaseRunner{}
 | 
				
			||||||
	var parentRunner *phaseRunner
 | 
						var parentRunner *phaseRunner
 | 
				
			||||||
	for _, phase := range e.Phases {
 | 
						for _, phase := range e.Phases {
 | 
				
			||||||
 | 
							// skips phases that are meant to create special subcommands only
 | 
				
			||||||
 | 
							if phase.RunAllSiblings {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// add phases to the execution list
 | 
				
			||||||
		addPhaseRunner(e, parentRunner, phase)
 | 
							addPhaseRunner(e, parentRunner, phase)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user