Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support single-user mode #185

Merged
merged 4 commits into from
Mar 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions local-debug.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ command -v operator-sdk >/dev/null 2>&1 || { echo -e $RED"operator-sdk is not in

CHE_NAMESPACE=che

set +e
kubectl create namespace $CHE_NAMESPACE
set -e

kubectl apply -f deploy/crds/org_v1_che_crd.yaml
kubectl apply -f $1 -n che
cp templates/keycloak_provision /tmp/keycloak_provision

operator-sdk up local --namespace=${CHE_NAMESPACE} --enable-delve
368 changes: 201 additions & 167 deletions pkg/controller/che/che_controller.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pkg/controller/che/che_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func TestCheController(t *testing.T) {
t.Fatalf("Failed to update %s CR: %s", cheCR.Name, err)
}
pvc := &corev1.PersistentVolumeClaim{}
if err = r.client.Get(context.TODO(), types.NamespacedName{Name: "postgres-data", Namespace: cheCR.Namespace}, pvc); err != nil {
if err = r.client.Get(context.TODO(), types.NamespacedName{Name: deploy.DefaultPostgresVolumeClaimName, Namespace: cheCR.Namespace}, pvc); err != nil {
t.Fatalf("Failed to get PVC: %s", err)
}
if err = r.client.Delete(context.TODO(), pvc); err != nil {
Expand All @@ -263,7 +263,7 @@ func TestCheController(t *testing.T) {
t.Fatalf("reconcile: (%v)", err)
}
pvc = &corev1.PersistentVolumeClaim{}
if err = r.client.Get(context.TODO(), types.NamespacedName{Name: "postgres-data", Namespace: cheCR.Namespace}, pvc); err != nil {
if err = r.client.Get(context.TODO(), types.NamespacedName{Name: deploy.DefaultPostgresVolumeClaimName, Namespace: cheCR.Namespace}, pvc); err != nil {
t.Fatalf("Failed to get PVC: %s", err)
}
actualStorageClassName := pvc.Spec.StorageClassName
Expand Down
170 changes: 87 additions & 83 deletions pkg/controller/che/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,101 +353,105 @@ func (r *ReconcileChe) CreateTLSSecret(instance *orgv1.CheCluster, url string, n

func (r *ReconcileChe) GenerateAndSaveFields(instance *orgv1.CheCluster, request reconcile.Request) (err error) {

chePostgresPassword := util.GetValue(instance.Spec.Database.ChePostgresPassword, util.GeneratePasswd(12))
if len(instance.Spec.Database.ChePostgresPassword) < 1 {
instance.Spec.Database.ChePostgresPassword = chePostgresPassword
if err := r.UpdateCheCRSpec(instance, "auto-generated CheCluster DB password", "password-hidden"); err != nil {
return err
}

}
keycloakPostgresPassword := util.GetValue(instance.Spec.Auth.IdentityProviderPostgresPassword, util.GeneratePasswd(12))
if len(instance.Spec.Auth.IdentityProviderPostgresPassword) < 1 {
instance.Spec.Auth.IdentityProviderPostgresPassword = keycloakPostgresPassword
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating passwd")
} else {
keycloakPostgresPassword = util.GetDeploymentEnv(keycloakDeployment, "DB_PASSWORD")
}
if err := r.UpdateCheCRSpec(instance, "auto-generated Keycloak DB password", "password-hidden"); err != nil {
cheFlavor := util.GetValue(instance.Spec.Server.CheFlavor, deploy.DefaultCheFlavor)
if len(instance.Spec.Server.CheFlavor) < 1 {
instance.Spec.Server.CheFlavor = cheFlavor
if err := r.UpdateCheCRSpec(instance, "installation flavor", cheFlavor); err != nil {
return err
}
}
if len(instance.Spec.Auth.IdentityProviderPassword) < 1 {
keycloakAdminPassword := util.GetValue(instance.Spec.Auth.IdentityProviderPassword, util.GeneratePasswd(12))
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating passwd")
} else {
keycloakAdminPassword = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_PASSWORD")
}
instance.Spec.Auth.IdentityProviderPassword = keycloakAdminPassword
if err := r.UpdateCheCRSpec(instance, "Keycloak admin password", "password hidden"); err != nil {
return err

cheMultiUser := deploy.GetCheMultiUser(instance)
if cheMultiUser == "true" {
chePostgresPassword := util.GetValue(instance.Spec.Database.ChePostgresPassword, util.GeneratePasswd(12))
if len(instance.Spec.Database.ChePostgresPassword) < 1 {
instance.Spec.Database.ChePostgresPassword = chePostgresPassword
if err := r.UpdateCheCRSpec(instance, "auto-generated CheCluster DB password", "password-hidden"); err != nil {
return err
}

}
}
if len(instance.Spec.Auth.IdentityProviderAdminUserName) < 1 {
keycloakAdminUserName := util.GetValue(instance.Spec.Auth.IdentityProviderAdminUserName, "admin")
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating admin username")
} else {
keycloakAdminUserName = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_USERNAME")
keycloakPostgresPassword := util.GetValue(instance.Spec.Auth.IdentityProviderPostgresPassword, util.GeneratePasswd(12))
if len(instance.Spec.Auth.IdentityProviderPostgresPassword) < 1 {
instance.Spec.Auth.IdentityProviderPostgresPassword = keycloakPostgresPassword
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating passwd")
} else {
keycloakPostgresPassword = util.GetDeploymentEnv(keycloakDeployment, "DB_PASSWORD")
}
if err := r.UpdateCheCRSpec(instance, "auto-generated Keycloak DB password", "password-hidden"); err != nil {
return err
}
}
instance.Spec.Auth.IdentityProviderAdminUserName = keycloakAdminUserName
if err := r.UpdateCheCRSpec(instance, "Keycloak admin username", keycloakAdminUserName); err != nil {
return err
if len(instance.Spec.Auth.IdentityProviderPassword) < 1 {
keycloakAdminPassword := util.GetValue(instance.Spec.Auth.IdentityProviderPassword, util.GeneratePasswd(12))
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating passwd")
} else {
keycloakAdminPassword = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_PASSWORD")
}
instance.Spec.Auth.IdentityProviderPassword = keycloakAdminPassword
if err := r.UpdateCheCRSpec(instance, "Keycloak admin password", "password hidden"); err != nil {
return err
}
}
}
chePostgresUser := util.GetValue(instance.Spec.Database.ChePostgresUser, "pgche")
if len(instance.Spec.Database.ChePostgresUser) < 1 {
instance.Spec.Database.ChePostgresUser = chePostgresUser
if err := r.UpdateCheCRSpec(instance, "Postgres User", chePostgresUser); err != nil {
return err
if len(instance.Spec.Auth.IdentityProviderAdminUserName) < 1 {
keycloakAdminUserName := util.GetValue(instance.Spec.Auth.IdentityProviderAdminUserName, "admin")
keycloakDeployment, err := r.GetEffectiveDeployment(instance, "keycloak")
if err != nil {
logrus.Info("Disregard the error. No existing Identity provider deployment found. Generating admin username")
} else {
keycloakAdminUserName = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_USERNAME")
}
instance.Spec.Auth.IdentityProviderAdminUserName = keycloakAdminUserName
if err := r.UpdateCheCRSpec(instance, "Keycloak admin username", keycloakAdminUserName); err != nil {
return err
}
}
}
chePostgresDb := util.GetValue(instance.Spec.Database.ChePostgresDb, "dbche")
if len(instance.Spec.Database.ChePostgresDb) < 1 {
instance.Spec.Database.ChePostgresDb = chePostgresDb
if err := r.UpdateCheCRSpec(instance, "Postgres DB", chePostgresDb); err != nil {
return err
chePostgresUser := util.GetValue(instance.Spec.Database.ChePostgresUser, "pgche")
if len(instance.Spec.Database.ChePostgresUser) < 1 {
instance.Spec.Database.ChePostgresUser = chePostgresUser
if err := r.UpdateCheCRSpec(instance, "Postgres User", chePostgresUser); err != nil {
return err
}
}
}
chePostgresHostName := util.GetValue(instance.Spec.Database.ChePostgresHostName, deploy.DefaultChePostgresHostName)
if len(instance.Spec.Database.ChePostgresHostName) < 1 {
instance.Spec.Database.ChePostgresHostName = chePostgresHostName
if err := r.UpdateCheCRSpec(instance, "Postgres hostname", chePostgresHostName); err != nil {
return err
chePostgresDb := util.GetValue(instance.Spec.Database.ChePostgresDb, "dbche")
if len(instance.Spec.Database.ChePostgresDb) < 1 {
instance.Spec.Database.ChePostgresDb = chePostgresDb
if err := r.UpdateCheCRSpec(instance, "Postgres DB", chePostgresDb); err != nil {
return err
}
}
}
chePostgresPort := util.GetValue(instance.Spec.Database.ChePostgresPort, deploy.DefaultChePostgresPort)
if len(instance.Spec.Database.ChePostgresPort) < 1 {
instance.Spec.Database.ChePostgresPort = chePostgresPort
if err := r.UpdateCheCRSpec(instance, "Postgres port", chePostgresPort); err != nil {
return err
chePostgresHostName := util.GetValue(instance.Spec.Database.ChePostgresHostName, deploy.DefaultChePostgresHostName)
if len(instance.Spec.Database.ChePostgresHostName) < 1 {
instance.Spec.Database.ChePostgresHostName = chePostgresHostName
if err := r.UpdateCheCRSpec(instance, "Postgres hostname", chePostgresHostName); err != nil {
return err
}
}
}
cheFlavor := util.GetValue(instance.Spec.Server.CheFlavor, deploy.DefaultCheFlavor)
if len(instance.Spec.Server.CheFlavor) < 1 {
instance.Spec.Server.CheFlavor = cheFlavor
if err := r.UpdateCheCRSpec(instance, "installation flavor", cheFlavor); err != nil {
return err
chePostgresPort := util.GetValue(instance.Spec.Database.ChePostgresPort, deploy.DefaultChePostgresPort)
if len(instance.Spec.Database.ChePostgresPort) < 1 {
instance.Spec.Database.ChePostgresPort = chePostgresPort
if err := r.UpdateCheCRSpec(instance, "Postgres port", chePostgresPort); err != nil {
return err
}
}
}
keycloakRealm := util.GetValue(instance.Spec.Auth.IdentityProviderRealm, cheFlavor)
if len(instance.Spec.Auth.IdentityProviderRealm) < 1 {
instance.Spec.Auth.IdentityProviderRealm = keycloakRealm
if err := r.UpdateCheCRSpec(instance, "Keycloak realm", keycloakRealm); err != nil {
return err
keycloakRealm := util.GetValue(instance.Spec.Auth.IdentityProviderRealm, cheFlavor)
if len(instance.Spec.Auth.IdentityProviderRealm) < 1 {
instance.Spec.Auth.IdentityProviderRealm = keycloakRealm
if err := r.UpdateCheCRSpec(instance, "Keycloak realm", keycloakRealm); err != nil {
return err
}
}
}
keycloakClientId := util.GetValue(instance.Spec.Auth.IdentityProviderClientId, cheFlavor+"-public")
if len(instance.Spec.Auth.IdentityProviderClientId) < 1 {
instance.Spec.Auth.IdentityProviderClientId = keycloakClientId
keycloakClientId := util.GetValue(instance.Spec.Auth.IdentityProviderClientId, cheFlavor+"-public")
if len(instance.Spec.Auth.IdentityProviderClientId) < 1 {
instance.Spec.Auth.IdentityProviderClientId = keycloakClientId

if err := r.UpdateCheCRSpec(instance, "Keycloak client ID", keycloakClientId); err != nil {
return err
if err := r.UpdateCheCRSpec(instance, "Keycloak client ID", keycloakClientId); err != nil {
return err
}
}
}

Expand Down Expand Up @@ -510,7 +514,7 @@ func (r *ReconcileChe) GenerateAndSaveFields(instance *orgv1.CheCluster, request
}

if deploy.MigratingToCRW2_0(instance) &&
! instance.Spec.Server.ExternalPluginRegistry &&
!instance.Spec.Server.ExternalPluginRegistry &&
instance.Spec.Server.PluginRegistryUrl == deploy.OldCrwPluginRegistryUrl {
instance.Spec.Server.PluginRegistryUrl = ""
if err := r.UpdateCheCRSpec(instance, "plugin registry url", instance.Spec.Server.PluginRegistryUrl); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/che/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (cl *k8s) RunExec(command []string, podName, namespace string) (string, str
return stdout.String(), stderr.String(), nil
}

func (r *ReconcileChe) CreateKyecloakResources(instance *orgv1.CheCluster, request reconcile.Request, deploymentName string) (err error) {
func (r *ReconcileChe) CreateKeycloakResources(instance *orgv1.CheCluster, request reconcile.Request, deploymentName string) (err error) {
cheHost := instance.Spec.Server.CheHost
keycloakProvisionCommand := deploy.GetKeycloakProvisionCommand(instance, cheHost)
podToExec, err := k8sclient.GetDeploymentPod(deploymentName, instance.Namespace)
Expand Down
70 changes: 50 additions & 20 deletions pkg/controller/che/k8s_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@ import (
"context"
"crypto/tls"
"encoding/pem"
"io"
"net/http"
"time"

orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/eclipse/che-operator/pkg/deploy"
"github.com/eclipse/che-operator/pkg/util"
routev1 "github.com/openshift/api/route/v1"
"github.com/sirupsen/logrus"
"io"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"net/http"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"time"
)

type k8s struct {
Expand All @@ -56,8 +57,8 @@ func GetK8Client() *k8s {
return nil
}

// GetPostgresStatus waits for pvc.status.phase to be Bound
func (cl *k8s) GetPostgresStatus(pvc *corev1.PersistentVolumeClaim, ns string) {
// GetPVCStatus waits for pvc.status.phase to be Bound
func (cl *k8s) GetPVCStatus(pvc *corev1.PersistentVolumeClaim, ns string) {
// short timeout if a PVC is waiting for a first consumer to be bound
var timeout int64 = 10
listOptions := metav1.ListOptions{
Expand All @@ -78,33 +79,33 @@ func (cl *k8s) GetPostgresStatus(pvc *corev1.PersistentVolumeClaim, ns string) {
}

// check before watching in case pvc has been already bound
postgresPvc, err := cl.clientset.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
chePvc, err := cl.clientset.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
if err != nil {
logrus.Errorf("Failed to get %s pvc: %s", postgresPvc.Name, err)
logrus.Errorf("Failed to get %s pvc: %s", chePvc.Name, err)
break
}
if postgresPvc.Status.Phase == "Bound" {
volumeName := postgresPvc.Spec.VolumeName
logrus.Infof("PVC %s successfully bound to volume %s", postgresPvc.Name, volumeName)
if chePvc.Status.Phase == "Bound" {
volumeName := chePvc.Spec.VolumeName
logrus.Infof("PVC %s successfully bound to volume %s", chePvc.Name, volumeName)
break
}

switch event.Type {
case watch.Error:
watcher.Stop()
case watch.Modified:
if postgresPvc.Status.Phase == "Bound" {
volumeName := postgresPvc.Spec.VolumeName
logrus.Infof("PVC %s successfully bound to volume %s", postgresPvc.Name, volumeName)
if chePvc.Status.Phase == "Bound" {
volumeName := chePvc.Spec.VolumeName
logrus.Infof("PVC %s successfully bound to volume %s", chePvc.Name, volumeName)
watcher.Stop()
}

}
}
postgresPvc, err := cl.clientset.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
if postgresPvc.Status.Phase != "Bound" {
currentPvcPhase := postgresPvc.Status.Phase
logrus.Warnf("Timeout waiting for a PVC %s to be bound. Current phase is %s", postgresPvc.Name, currentPvcPhase)
chePvc, err := cl.clientset.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
if chePvc.Status.Phase != "Bound" {
currentPvcPhase := chePvc.Status.Phase
logrus.Warnf("Timeout waiting for a PVC %s to be bound. Current phase is %s", chePvc.Name, currentPvcPhase)
logrus.Warn("Sometimes PVC can be bound only when the first consumer is created")
}
}
Expand Down Expand Up @@ -220,11 +221,40 @@ func (cl *k8s) GetEvents(deploymentName string, ns string) (list *corev1.EventLi
return deploymentEvents
}

func (cl *k8s) IsPVCExists(pvcName string, ns string) bool {
getOptions := metav1.GetOptions{}
_, err := cl.clientset.CoreV1().PersistentVolumeClaims(ns).Get(pvcName, getOptions)
return err == nil
}

func (cl *k8s) DeletePVC(pvcName string, ns string) {
logrus.Infof("Deleting PVC: %s", pvcName)
deleteOptions := &metav1.DeleteOptions{}
err := cl.clientset.CoreV1().PersistentVolumeClaims(ns).Delete(pvcName, deleteOptions)
if err != nil {
logrus.Errorf("PVC deletion error: %v", err)
}
}

func (cl *k8s) IsDeploymentExists(deploymentName string, ns string) bool {
getOptions := metav1.GetOptions{}
_, err := cl.clientset.AppsV1().Deployments(ns).Get(deploymentName, getOptions)
return err == nil
}

func (cl *k8s) DeleteDeployment(deploymentName string, ns string) {
logrus.Infof("Deleting deployment: %s", deploymentName)
deleteOptions := &metav1.DeleteOptions{}
err := cl.clientset.AppsV1().Deployments(ns).Delete(deploymentName, deleteOptions)
if err != nil {
logrus.Errorf("Deployment deletion error: %v", err)
}
}

// GetLogs prints stderr or stdout from a selected pod. Log size is capped at 60000 bytes
func (cl *k8s) GetPodLogs(podName string, ns string) () {
func (cl *k8s) GetPodLogs(podName string, ns string) {
var limitBytes int64 = 60000
req := cl.clientset.CoreV1().Pods(ns).GetLogs(podName, &corev1.PodLogOptions{LimitBytes: &limitBytes},
)
req := cl.clientset.CoreV1().Pods(ns).GetLogs(podName, &corev1.PodLogOptions{LimitBytes: &limitBytes})
readCloser, err := req.Stream()
if err != nil {
logrus.Errorf("Pod error log: %v", err)
Expand Down
Loading