diff --git a/api/v2/checluster_webhook.go b/api/v2/checluster_webhook.go index e177e929b..ee05b340e 100644 --- a/api/v2/checluster_webhook.go +++ b/api/v2/checluster_webhook.go @@ -20,6 +20,7 @@ import ( "github.com/eclipse-che/che-operator/pkg/common/constants" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/json" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" k8shelper "github.com/eclipse-che/che-operator/pkg/common/k8s-helper" corev1 "k8s.io/api/core/v1" @@ -43,6 +44,9 @@ var _ webhook.Validator = &CheCluster{} // ValidateCreate implements webhook.Validator so a webhook will be registered for the type func (r *CheCluster) ValidateCreate() error { + if err := ensureSingletonCheCluster(); err != nil { + return err + } return validate(r) } @@ -56,6 +60,23 @@ func (r *CheCluster) ValidateDelete() error { return nil } +func ensureSingletonCheCluster() error { + client := k8shelper.New().GetClient() + utilruntime.Must(AddToScheme(client.Scheme())) + + che := &CheClusterList{} + err := client.List(context.TODO(), che) + if err != nil { + logger.Error(err, "Failed to list CheCluster Custom Resources.") + } + + if len(che.Items) != 0 { + return fmt.Errorf("only one CheCluster is allowed") + } + + return nil +} + func validate(checluster *CheCluster) error { for _, github := range checluster.Spec.GitServices.GitHub { if err := validateGitHubOAuthSecret(github, checluster.Namespace); err != nil { diff --git a/pkg/common/k8s-helper/k8s_helper.go b/pkg/common/k8s-helper/k8s_helper.go index c4c49c3ea..91dde5327 100644 --- a/pkg/common/k8s-helper/k8s_helper.go +++ b/pkg/common/k8s-helper/k8s_helper.go @@ -18,6 +18,10 @@ import ( "io" "os" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + "k8s.io/client-go/kubernetes/fake" "github.com/sirupsen/logrus" @@ -31,6 +35,7 @@ import ( type K8sHelper struct { clientset kubernetes.Interface + client client.Client } var ( @@ -53,6 +58,10 @@ func (cl *K8sHelper) GetClientset() kubernetes.Interface { return cl.clientset } +func (cl *K8sHelper) GetClient() client.Client { + return cl.client +} + func (cl *K8sHelper) ExecIntoPod( deploymentName string, command string, @@ -159,6 +168,7 @@ func (cl *K8sHelper) RunExec(command []string, podName, namespace string, stdin func initializeForTesting() *K8sHelper { k8sHelper = &K8sHelper{ clientset: fake.NewSimpleClientset(), + client: fakeclient.NewClientBuilder().Build(), } return k8sHelper @@ -175,8 +185,14 @@ func initialize() *K8sHelper { logrus.Fatalf("Failed to initialized Kubernetes client: %v", err) } + client, err := client.New(cfg, client.Options{Scheme: runtime.NewScheme()}) + if err != nil { + logrus.Fatalf("Failed to initialized Kubernetes client: %v", err) + } + k8sHelper = &K8sHelper{ clientset: clientSet, + client: client, } return k8sHelper