More tests. New defaults. Custom CM. Updates to README

pull/6/head
Eugene Ivantsov 2019-03-27 20:09:03 +02:00
parent 48db0ea5b8
commit bb1034b380
16 changed files with 200 additions and 52 deletions

View File

@ -54,9 +54,9 @@ When enabling TLS, make sure you create a secret with crt and key, and let the O
## How to Configure
The operator watches all objects it creates and reconciles them with CR state. It means that if you edit, say, a configMap che, the operator will revert changes.
Since not all Che configuration properties are custom resource spec fields, the operator creates a second configMap called custom. You can use this configmap
for any configuration that is not supported by CR.
The operator watches all objects it creates and reconciles them with CR state. It means that if you edit a configMap **che**, the operator will revert changes.
Since not all Che configuration properties are custom resource spec fields (there are too many of them), the operator creates a second configMap called **custom**
which you can use for any environment variables not supported by CR. The operator will not reconcile configMap custom.
## How to Build Operator Image

View File

@ -10,7 +10,7 @@
# Contributors:
# Red Hat, Inc. - initial API and implementation
set -e
#set -e
BASE_DIR=$(cd "$(dirname "$0")"; pwd)
@ -22,7 +22,9 @@ kubectl apply -f ${BASE_DIR}/deploy/crds/org_v1_che_crd.yaml -n=$1
# sometimes the operator cannot get CRD right away
sleep 2
# uncomment when on OpenShift if you need to use self signed certs and login with OpenShift in Che
#oc adm policy add-cluster-role-to-user cluster-admin -z che-operator -n=$1
kubectl apply -f ${BASE_DIR}/operator-local.yaml -n=$1
#oc new-app -f ${BASE_DIR}/deploy/role_binding_oauth.yaml -p NAMESPACE=$1 -n=$1
#oc apply -f ${BASE_DIR}/deploy/cluster_role.yaml -n=$1
#oc new-app -f ${BASE_DIR}/deploy/role_binding_crt.yaml -p NAMESPACE=$1
#oc apply -f ${BASE_DIR}/deploy/role_get_tls.yaml
kubectl apply -f ${BASE_DIR}/deploy/operator-local.yaml -n=$1
kubectl apply -f ${BASE_DIR}/deploy/crds/org_v1_che_cr.yaml -n=$1

View File

@ -19,7 +19,12 @@ oc apply -f ${BASE_DIR}/role_binding.yaml
oc apply -f ${BASE_DIR}/crds/org_v1_che_crd.yaml
# sometimes the operator cannot get CRD right away
sleep 2
# uncomment if you need Login with OpenShift and/or use self signed certificates and tls
#oc adm policy add-cluster-role-to-user cluster-admin -z che-operator
oc apply -f ${BASE_DIR}/operator.yaml
oc apply -f ${BASE_DIR}/crds/org_v1_che_cr.yaml
#oc new-app -f ${BASE_DIR}deploy/role_binding_oauth.yaml -p NAMESPACE=$1 -n=$1
#oc apply -f ${BASE_DIR}deploy/cluster_role.yaml -n=$1
#oc new-app -f ${BASE_DIR}deploy/role_binding_crt.yaml -p NAMESPACE=$1
#oc apply -f ${BASE_DIR}deploy/role_get_tls.yaml
oc apply -f ${BASE_DIR}/deploy/operator.yaml
oc apply -f ${BASE_DIR}/deploy/crds/org_v1_che_cr.yaml

21
deploy/cluster_role.yaml Normal file
View File

@ -0,0 +1,21 @@
#
# Copyright (c) 2012-2019 Red Hat, Inc.
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Red Hat, Inc. - initial API and implementation
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: che-operator
rules:
- apiGroups:
- oauth.openshift.io
resources:
- "*"
verbs:
- "*"

View File

@ -45,7 +45,7 @@ spec:
# otherwise a Postgres deployment is created
externalDb:
# Postgres Database hostname that Che server uses to connect to. Defaults to postgres
chePostgresHostname: ''
chePostgresHostName: ''
# Postgres Database port that Che server uses to connect to. Defaults to 5432
chePostgresPort: ''
# Postgres user that Che server when making a db connection. Defaults to pgche

View File

@ -25,7 +25,7 @@ spec:
serviceAccountName: che-operator
containers:
- name: che-operator
image: eivantsov/operator-container
image: eivantsov/operator
ports:
- containerPort: 60000
name: metrics

View File

@ -8,12 +8,12 @@
#
# Contributors:
# Red Hat, Inc. - initial API and implementation
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
creationTimestamp: null
name: che-operator
rules:
- apiGroups:
- extensions/v1beta1
@ -32,6 +32,11 @@ rules:
resources:
- roles
- rolebindings
verbs:
- "*"
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterroles
- clusterrolebindings
verbs:
@ -75,4 +80,4 @@ rules:
resources:
- '*'
verbs:
- '*'
- '*'

View File

@ -0,0 +1,33 @@
#
# Copyright (c) 2012-2019 Red Hat, Inc.
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Red Hat, Inc. - initial API and implementation
kind: Template
apiVersion: v1
metadata:
name: che-operator
objects:
- kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: che-operator
namespace: default
subjects:
- kind: ServiceAccount
name: che-operator
namespace: ${NAMESPACE}
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
parameters:
- name: NAMESPACE
displayName: Namespace
description: Namespace
required: true

View File

@ -0,0 +1,32 @@
#
# Copyright (c) 2012-2019 Red Hat, Inc.
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Red Hat, Inc. - initial API and implementation
kind: Template
apiVersion: v1
metadata:
name: che-operator
objects:
- kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: che-operator
subjects:
- kind: ServiceAccount
name: che-operator
namespace: ${NAMESPACE}
roleRef:
kind: ClusterRole
name: che-operator
apiGroup: rbac.authorization.k8s.io
parameters:
- name: NAMESPACE
displayName: Namespace
description: Namespace
required: true

30
deploy/role_get_tls.yaml Normal file
View File

@ -0,0 +1,30 @@
#
# Copyright (c) 2012-2019 Red Hat, Inc.
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Red Hat, Inc. - initial API and implementation
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
#---
#kind: Role
#apiVersion: rbac.authorization.k8s.io/v1
#metadata:
# namespace: openshift-ingress
# name: secret-reader-4-0
#rules:
# - apiGroups: [""]
# resources: ["secrets"]
# verbs: ["get"]

View File

@ -41,7 +41,7 @@ import (
var log = logf.Log.WithName("controller_che")
var (
k8sclient = GetK8Client()
k8sclient = GetK8Client()
)
// Add creates a new CheCluster Controller and adds it to the Manager. The Manager will set fields on the Controller
@ -474,7 +474,8 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
}
// create Che ConfigMap
// create Che ConfigMap which is synced with CR and is not supposed to be manually edited
// controller will reconcile this CM with CR spec
cheHost := instance.Spec.Server.CheHost
cheEnv := deploy.GetConfigMapData(instance)
cheConfigMap := deploy.NewCheConfigMap(instance, cheEnv)
@ -482,10 +483,10 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
return reconcile.Result{}, err
}
// create a custom configmap that won't be synced with CR spec
// to be able to override envs and not clutter CR spec with fields
// create a custom ConfigMap that won't be synced with CR spec
// to be able to override envs and not clutter CR spec with fields which are too numerous
customCM := &corev1.ConfigMap{
Data: map[string]string{"SAMPLE_KEY": "SAMPLE_VALUE"},
Data: deploy.GetCustomConfigMapData(),
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap"},
ObjectMeta: metav1.ObjectMeta{
@ -495,7 +496,8 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
if err := r.CreateNewConfigMap(instance, customCM); err != nil {
return reconcile.Result{}, err
}
// configMap resource version will be an env in Che deployment to easily update it when a ConfigMap changes
// which will automatically trigger Che rolling update
cmResourceVersion := cheConfigMap.ResourceVersion
// create Che deployment
cheImageRepo := util.GetValue(instance.Spec.Server.CheImage, deploy.DefaultCheServerImageRepo)
@ -515,7 +517,6 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
logrus.Errorf("Failed to get %s deployment: %s", cheDeployment.Name, err)
return reconcile.Result{}, err
}
if !tests {
if deployment.Status.AvailableReplicas != 1 {
instance, _ := r.GetCR(request)

View File

@ -14,7 +14,9 @@ package che
import (
"context"
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
oauth "github.com/openshift/api/oauth/v1"
routev1 "github.com/openshift/api/route/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -23,7 +25,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
oauth "github.com/openshift/api/oauth/v1"
"testing"
)
@ -134,7 +135,6 @@ func TestCheController(t *testing.T) {
if err := cl.Update(context.TODO(), cheCR); err != nil {
t.Error("Failed to update CheCluster custom resource")
}
// reconcile again
res, err = r.Reconcile(req)
if err != nil {
t.Fatalf("reconcile: (%v)", err)
@ -154,7 +154,7 @@ func TestCheController(t *testing.T) {
}
err = r.client.Get(context.TODO(), types.NamespacedName{Name: cheCR.Name, Namespace: cheCR.Namespace}, cheCR)
err = r.CreateIdentityProviderItems(cheCR,req, "che", "keycloak")
err = r.CreateIdentityProviderItems(cheCR, req, "che", "keycloak")
oAuthClientName := cheCR.Spec.Auth.OauthClientName
oauthSecret := cheCR.Spec.Auth.OauthSecret
if err = r.client.Get(context.TODO(), types.NamespacedName{Name: oAuthClientName, Namespace: ""}, oAuthClient); err != nil {
@ -164,4 +164,20 @@ func TestCheController(t *testing.T) {
t.Errorf("Secrets do not match. Expecting %s, got %s", oauthSecret, oAuthClient.Secret)
}
// check if a new Postgres deployment is not created when spec.Database.ExternalDB is true
cheCR.Spec.Database.ExternalDB = true
if err := cl.Update(context.TODO(), cheCR); err != nil {
t.Error("Failed to update CheCluster custom resource")
}
postgresDeployment := &appsv1.Deployment{}
err = r.client.Get(context.TODO(), types.NamespacedName{Name: "postgres", Namespace: cheCR.Namespace}, postgresDeployment)
err = r.client.Delete(context.TODO(), postgresDeployment)
res, err = r.Reconcile(req)
if err != nil {
t.Fatalf("reconcile: (%v)", err)
}
err = r.client.Get(context.TODO(), types.NamespacedName{Name: "postgres", Namespace: cheCR.Namespace}, postgresDeployment)
if err == nil {
t.Fatalf("Deployment postgres shoud not exist")
}
}

View File

@ -185,10 +185,6 @@ func (r *ReconcileChe) CreateNewSecret(instance *orgv1.CheCluster, secret *corev
}
func (r *ReconcileChe) CreateNewOauthClient(instance *orgv1.CheCluster, oAuthClient *oauth.OAuthClient) error {
if err := controllerutil.SetControllerReference(instance, oAuthClient, r.scheme); err != nil {
logrus.Errorf("An error occurred: %s", err)
return err
}
oAuthClientFound := &oauth.OAuthClient{}
err := r.client.Get(context.TODO(), types.NamespacedName{Name: oAuthClient.Name, Namespace: oAuthClient.Namespace}, oAuthClientFound)
if err != nil && errors.IsNotFound(err) {

View File

@ -50,6 +50,7 @@ func GetK8Client() *k8s {
// GetPostgresStatus waits for pvc.status.phase to be Bound
func (cl *k8s) GetPostgresStatus(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{
FieldSelector: fields.OneTermEqualSelector("metadata.name", pvc.Name).String(),

View File

@ -51,11 +51,6 @@ type CheConfigMap struct {
KeycloakRealm string `json:"CHE_KEYCLOAK_REALM"`
KeycloakClientId string `json:"CHE_KEYCLOAK_CLIENT__ID"`
OpenShiftIdentityProvider string `json:"CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"`
ReloadStacksOnStart string `json:"CHE_PREDEFINED_STACKS_RELOAD__ON__START"`
WorkspaceServiceAccountName string `json:"CHE_INFRA_KUBERNETES_SERVICE__ACCOUNT__NAME"`
WorkspaceAutoStart string `json:"CHE_WORKSPACE_AUTO_START"`
UnrecoverableEvents string `json:"CHE_INFRA_KUBERNETES_WORKSPACE__UNRECOVERABLE__EVENTS"`
InactiveWorkspaceStopTimeout string `json:"CHE_WORKSPACE_AGENT_DEV_INACTIVE__STOP__TIMEOUT__MS"`
JavaOpts string `json:"JAVA_OPTS"`
WorkspaceJavaOpts string `json:"CHE_WORKSPACE_JAVA__OPTIONS"`
WorkspaceMavenOpts string `json:"CHE_WORKSPACE_MAVEN__OPTIONS"`
@ -67,6 +62,19 @@ type CheConfigMap struct {
WebSocketEndpointMinor string `json:"CHE_WEBSOCKET_ENDPOINT__MINOR"`
}
func GetCustomConfigMapData()(cheEnv map[string]string) {
cheEnv = map[string]string{
"CHE_PREDEFINED_STACKS_RELOAD__ON__START": "true",
"CHE_INFRA_KUBERNETES_SERVICE__ACCOUNT__NAME": "che-workspace",
"CHE_WORKSPACE_AUTO_START": "true",
"CHE_INFRA_KUBERNETES_WORKSPACE__UNRECOVERABLE__EVENTS": "FailedMount,FailedScheduling,MountVolume.SetUp failed,Failed to pull image",
"CHE_WORKSPACE_AGENT_DEV_INACTIVE__STOP__TIMEOUT__MS": "-1",
}
return cheEnv
}
// GetConfigMapData gets env values from CR spec and returns a map with key:value
// which is used in CheCluster ConfigMap to configure CheCluster master behavior
func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
@ -156,24 +164,14 @@ func GetConfigMapData(cr *orgv1.CheCluster) (cheEnv map[string]string) {
KeycloakRealm: keycloakRealm,
KeycloakClientId: keycloakClientId,
OpenShiftIdentityProvider: openShiftIdentityProviderId,
ReloadStacksOnStart: "true",
WorkspaceServiceAccountName: "che-workspace",
WorkspaceAutoStart: "true",
UnrecoverableEvents: "FailedMount,FailedScheduling,MountVolume.SetUp failed,Failed to pull image",
InactiveWorkspaceStopTimeout: "-1",
JavaOpts: "-XX:MaxRAMFraction=2 -XX:+UseParallelGC -XX:MinHeapFreeRatio=10 " +
"-XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 " +
"-XX:AdaptiveSizePolicyWeight=90 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " +
"-Dsun.zip.disableMemoryMapping=true -Xms20m " + proxyJavaOpts,
WorkspaceJavaOpts: "-XX:MaxRAM=150m -XX:MaxRAMFraction=2 -XX:+UseParallelGC " +
"-XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 " +
"-Dsun.zip.disableMemoryMapping=true " +
"-Xms20m -Djava.security.egd=file:/dev/./urandom " + proxyJavaOpts,
WorkspaceProxyJavaOpts: proxyJavaOpts,
WorkspaceHttpProxy: cheWorkspaceHttpProxy,
WorkspaceHttpsProxy: cheWorkspaceHttpProxy,
WorkspaceNoProxy: cheWorkspaceNoProxy,
PluginRegistryUrl: pluginRegistryUrl,
JavaOpts: DefaultJavaOpts + " " + proxyJavaOpts,
WorkspaceJavaOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
WorkspaceMavenOpts: DefaultWorkspaceJavaOpts + " " + proxyJavaOpts,
WorkspaceProxyJavaOpts: proxyJavaOpts,
WorkspaceHttpProxy: cheWorkspaceHttpProxy,
WorkspaceHttpsProxy: cheWorkspaceHttpProxy,
WorkspaceNoProxy: cheWorkspaceNoProxy,
PluginRegistryUrl: pluginRegistryUrl,
}
out, err := json.Marshal(data)

View File

@ -14,7 +14,7 @@ package deploy
const (
DefaultCheServerImageRepo = "eclipse/che-server"
DefaultCodeReadyServerImageRepo = "registry.access.redhat.com/codeready-workspaces/server"
DefaultCheServerImageTag = "6.19.0"
DefaultCheServerImageTag = "7.0.0-beta-2.0"
DefaultCodeReadyServerImageTag = "1.1"
DefaultCheFlavor = "che"
DefaultChePostgresUser = "pgche"
@ -34,4 +34,12 @@ const (
DefaultPostgresUpstreamImage = "centos/postgresql-96-centos7:9.6"
DefaultKeycloakImage = "registry.access.redhat.com/redhat-sso-7/sso72-openshift:1.2-8"
DefaultKeycloakUpstreamImage = "eclipse/che-keycloak:6.19.0"
DefaultJavaOpts = "-XX:MaxRAMFraction=2 -XX:+UseParallelGC -XX:MinHeapFreeRatio=10 " +
"-XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 " +
"-XX:AdaptiveSizePolicyWeight=90 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " +
"-Dsun.zip.disableMemoryMapping=true -Xms20m"
DefaultWorkspaceJavaOpts = "-XX:MaxRAM=150m -XX:MaxRAMFraction=2 -XX:+UseParallelGC " +
"-XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 " +
"-Dsun.zip.disableMemoryMapping=true " +
"-Xms20m -Djava.security.egd=file:/dev/./urandom"
)