Code clean up 3 (#753)

* Code clean up part 3

Signed-off-by: Anatolii Bazko <abazko@redhat.com>
pull/758/head
Anatolii Bazko 2021-04-07 14:55:14 +03:00 committed by GitHub
parent 92d317caf5
commit fa39d6f79e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 502 additions and 1477 deletions

View File

@ -1,35 +0,0 @@
#
# Copyright (c) 2012-2020 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
name: Minishift
on: pull_request
jobs:
minishift-e2e:
name: e2e tests
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: Provision Minishift cluster
run: |
brew install minishift
export MINISHIFT_GITHUB_API_TOKEN=${{ secrets.GITHUB_TOKEN }}
minishift start --memory=5500 --vm-driver=virtualbox
- name: Replace Minishift default certificates
run: /bin/bash .github/bin/minishift/certs.sh
- name: Run tests
run: |
eval $(minishift oc-env)
oc apply -f deploy/crds/org_v1_che_crd.yaml
go mod tidy
go run e2e/*.go
- uses: actions/upload-artifact@v2
with:
name: minishift-e2e-artifacts
path: /tmp/artifacts-che

View File

@ -26,10 +26,8 @@ oc apply -f ${BASE_DIR}/deploy/crds/org_v1_che_crd.yaml -n $NAMESPACE
# sometimes the operator cannot get CRD right away
sleep 2
# uncomment if you need Login with OpenShift
#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 $NAMESPACE
#oc apply -f ${BASE_DIR}/deploy/cluster_role_binding.yaml -n $NAMESPACE
oc apply -f ${BASE_DIR}/deploy/cluster_role.yaml -n $NAMESPACE
oc apply -f ${BASE_DIR}/deploy/cluster_role_binding.yaml -n $NAMESPACE
oc apply -f ${BASE_DIR}/deploy/operator.yaml -n $NAMESPACE
oc apply -f ${BASE_DIR}/deploy/crds/org_v1_che_cr.yaml -n $NAMESPACE

View File

@ -1,36 +0,0 @@
#
# 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
labels:
app.kubernetes.io/name: che
app.kubernetes.io/instance: che
app.kubernetes.io/component: 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

View File

@ -1,145 +0,0 @@
//
// 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
//
package main
import (
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
oauth "github.com/openshift/api/oauth/v1"
"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client/config"
)
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
clientSet, err = getClientSet()
oauthClientSet, _ = getOAuthClientSet()
client = GetK8Config()
SchemeGroupVersion = schema.GroupVersion{Group: groupName, Version: orgv1.SchemeGroupVersion.Version}
)
type k8s struct {
clientset kubernetes.Interface
}
type CRClient struct {
restClient rest.Interface
}
type OauthClient struct {
restClient rest.Interface
}
func GetK8Config() *k8s {
cfg, err := config.GetConfig()
if err != nil {
logrus.Errorf(err.Error())
}
client := k8s{}
client.clientset, err = kubernetes.NewForConfig(cfg)
if err != nil {
logrus.Errorf(err.Error())
}
return &client
}
func getClientSet() (clientSet *CRClient, err error) {
cfg, err := config.GetConfig()
if err != nil {
logrus.Errorf(err.Error())
}
client := k8s{}
client.clientset, err = kubernetes.NewForConfig(cfg)
clientSet, err = newForConfig(cfg)
if err != nil {
return nil, err
}
return clientSet, nil
}
func getOAuthClientSet() (clientSet *OauthClient, err error) {
cfg, err := config.GetConfig()
if err != nil {
logrus.Errorf(err.Error())
}
client := k8s{}
client.clientset, err = kubernetes.NewForConfig(cfg)
clientSet, err = newOAuthConfig(cfg)
if err != nil {
return nil, err
}
return clientSet, nil
}
func getCR() (*orgv1.CheCluster, error) {
result := orgv1.CheCluster{}
opts := metav1.ListOptions{}
err = clientSet.restClient.
Get().
Namespace(namespace).
Resource(kind).
Name(crName).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
return nil, err
}
return &result, nil
}
func newForConfig(c *rest.Config) (*CRClient, error) {
config := *c
config.ContentConfig.GroupVersion = &schema.GroupVersion{Group: groupName, Version: orgv1.SchemeGroupVersion.Version}
//config.ContentConfig.GroupVersion = &schema.GroupVersion{Group: oauth.GroupName, Version: oauth.SchemeGroupVersion.Version}
config.APIPath = "/apis"
config.NegotiatedSerializer = serializer.WithoutConversionCodecFactory{CodecFactory: scheme.Codecs}
config.UserAgent = rest.DefaultKubernetesUserAgent()
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &CRClient{restClient: client}, nil
}
func newOAuthConfig(c *rest.Config) (*OauthClient, error) {
config := *c
config.ContentConfig.GroupVersion = &schema.GroupVersion{Group: oauth.GroupName, Version: oauth.SchemeGroupVersion.Version}
config.APIPath = "/apis"
config.NegotiatedSerializer = serializer.WithoutConversionCodecFactory{CodecFactory: scheme.Codecs}
config.UserAgent = rest.DefaultKubernetesUserAgent()
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &OauthClient{restClient: client}, nil
}
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&orgv1.CheCluster{},
&orgv1.CheClusterList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@ -1,149 +0,0 @@
//
// 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
//
package main
import (
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
"github.com/eclipse-che/che-operator/pkg/util"
"github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func createOperatorServiceAccount(operatorServiceAccount *corev1.ServiceAccount) (err error) {
operatorServiceAccount, err = client.clientset.CoreV1().ServiceAccounts(namespace).Create(operatorServiceAccount)
if err != nil {
logrus.Fatalf("Failed to create service account %s: %s", operatorServiceAccount.Name, err)
return err
}
return nil
}
func createOperatorServiceAccountRole(operatorServiceAccountRole *rbac.Role) (err error) {
operatorServiceAccountRole, err = client.clientset.RbacV1().Roles(namespace).Create(operatorServiceAccountRole)
if err != nil {
logrus.Fatalf("Failed to create role %s: %s", operatorServiceAccountRole.Name, err)
return err
}
return nil
}
func createOperatorServiceAccountClusterRole(operatorServiceAccountClusterRole *rbac.ClusterRole) (err error) {
operatorServiceAccountClusterRole, err = client.clientset.RbacV1().ClusterRoles().Create(operatorServiceAccountClusterRole)
if err != nil && !errors.IsAlreadyExists(err) {
logrus.Fatalf("Failed to create role %s: %s", operatorServiceAccountClusterRole.Name, err)
return err
}
return nil
}
func createOperatorServiceAccountRoleBinding(operatorServiceAccountRoleBinding *rbac.RoleBinding) (err error) {
operatorServiceAccountRoleBinding, err = client.clientset.RbacV1().RoleBindings(namespace).Create(operatorServiceAccountRoleBinding)
if err != nil {
logrus.Fatalf("Failed to create role %s: %s", operatorServiceAccountRoleBinding.Name, err)
return err
}
return nil
}
func createOperatorServiceAccountClusterRoleBinding(operatorServiceAccountClusterRoleBinding *rbac.ClusterRoleBinding) (err error) {
operatorServiceAccountClusterRoleBinding, err = client.clientset.RbacV1().ClusterRoleBindings().Create(operatorServiceAccountClusterRoleBinding)
if err != nil && !errors.IsAlreadyExists(err) {
logrus.Fatalf("Failed to create role %s: %s", operatorServiceAccountClusterRoleBinding.Name, err)
return err
}
return nil
}
func deployOperator(deployment *appsv1.Deployment) (err error) {
deployment, err = client.clientset.AppsV1().Deployments(namespace).Create(deployment)
if err != nil {
logrus.Fatalf("Failed to create deployment %s: %s", deployment.Name, err)
return err
}
return nil
}
func newNamespace() (ns *corev1.Namespace) {
return &corev1.Namespace{
TypeMeta: metav1.TypeMeta{
Kind: "Namespace",
APIVersion: corev1.SchemeGroupVersion.Version,
},
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
}
func createNamespace(ns *corev1.Namespace) (err error) {
ns, err = client.clientset.CoreV1().Namespaces().Create(ns)
if err != nil {
logrus.Warn(err)
return err
}
return nil
}
func newCheCluster() (cr *orgv1.CheCluster) {
cr = &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: crName,
},
TypeMeta: metav1.TypeMeta{
Kind: kind,
},
Spec: orgv1.CheClusterSpec{
Server: orgv1.CheClusterSpecServer{
UseInternalClusterSVCNames: true,
},
Auth: orgv1.CheClusterSpecAuth{
OpenShiftoAuth: util.NewBoolPointer(true),
},
},
}
return cr
}
func createCR() (err error) {
result := orgv1.CheCluster{}
cheCluster := newCheCluster()
err = clientSet.restClient.
Post().
Namespace(namespace).
Resource(kind).
Name(crName).
Body(cheCluster).
Do().
Into(&result)
if err != nil {
return err
}
return nil
}

View File

@ -1,23 +0,0 @@
//
// 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
//
package main
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func deleteNamespace() (err error) {
if err := client.clientset.CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{}); err != nil {
return err
}
return nil
}

View File

@ -1,142 +0,0 @@
//
// 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
//
package main
import (
"github.com/sirupsen/logrus"
"io/ioutil"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
"k8s.io/client-go/kubernetes/scheme"
"path/filepath"
)
func deserializeOperatorDeployment() (operatorDeployment *appsv1.Deployment, err error) {
fileLocation, err := filepath.Abs("deploy/operator.yaml")
if err != nil {
logrus.Fatalf("Failed to locate operator deployment yaml, %s", err)
}
file, err := ioutil.ReadFile(fileLocation)
if err != nil {
logrus.Errorf("Failed to locate operator deployment yaml, %s", err)
}
deployment := string(file)
decode := scheme.Codecs.UniversalDeserializer().Decode
object, _, err := decode([]byte(deployment), nil, nil)
if err != nil {
logrus.Errorf("Failed to deserialize yaml %s", err)
return nil, err
}
operatorDeployment = object.(*appsv1.Deployment)
return operatorDeployment, nil
}
func deserializeOperatorServiceAccount() (operatorServiceAccount *corev1.ServiceAccount, err error) {
fileLocation, err := filepath.Abs("deploy/service_account.yaml")
if err != nil {
logrus.Fatalf("Failed to locate operator service account yaml, %s", err)
}
file, err := ioutil.ReadFile(fileLocation)
if err != nil {
logrus.Errorf("Failed to locate operator service account yaml, %s", err)
}
sa := string(file)
decode := scheme.Codecs.UniversalDeserializer().Decode
object, _, err := decode([]byte(sa), nil, nil)
if err != nil {
logrus.Errorf("Failed to deserialize yaml %s", err)
return nil, err
}
operatorServiceAccount = object.(*corev1.ServiceAccount)
return operatorServiceAccount, nil
}
func deserializeOperatorRole() (operatorServiceAccountRole *rbac.Role, err error) {
fileLocation, err := filepath.Abs("deploy/role.yaml")
if err != nil {
logrus.Fatalf("Failed to locate operator service account role yaml, %s", err)
}
file, err := ioutil.ReadFile(fileLocation)
if err != nil {
logrus.Errorf("Failed to locate operator service account role yaml, %s", err)
}
role := string(file)
decode := scheme.Codecs.UniversalDeserializer().Decode
object, _, err := decode([]byte(role), nil, nil)
if err != nil {
logrus.Errorf("Failed to deserialize yaml %s", err)
return nil, err
}
operatorServiceAccountRole = object.(*rbac.Role)
return operatorServiceAccountRole, nil
}
func deserializeOperatorClusterRole() (operatorServiceAccountClusterRole *rbac.ClusterRole, err error) {
fileLocation, err := filepath.Abs("deploy/cluster_role.yaml")
if err != nil {
logrus.Fatalf("Failed to locate operator service account cluster role yaml, %s", err)
}
file, err := ioutil.ReadFile(fileLocation)
if err != nil {
logrus.Errorf("Failed to locate operator service account cluster role yaml, %s", err)
}
role := string(file)
decode := scheme.Codecs.UniversalDeserializer().Decode
object, _, err := decode([]byte(role), nil, nil)
if err != nil {
logrus.Errorf("Failed to deserialize yaml %s", err)
return nil, err
}
operatorServiceAccountClusterRole = object.(*rbac.ClusterRole)
return operatorServiceAccountClusterRole, nil
}
func deserializeOperatorRoleBinding() (operatorServiceAccountRoleBinding *rbac.RoleBinding, err error) {
fileLocation, err := filepath.Abs("deploy/role_binding.yaml")
if err != nil {
logrus.Fatalf("Failed to locate operator service account role binding yaml, %s", err)
}
file, err := ioutil.ReadFile(fileLocation)
if err != nil {
logrus.Errorf("Failed to locate operator service account role binding yaml, %s", err)
}
roleBinding := string(file)
decode := scheme.Codecs.UniversalDeserializer().Decode
object, _, err := decode([]byte(roleBinding), nil, nil)
if err != nil {
logrus.Errorf("Failed to deserialize yaml %s", err)
return nil, err
}
operatorServiceAccountRoleBinding = object.(*rbac.RoleBinding)
return operatorServiceAccountRoleBinding, nil
}
func deserializeOperatorClusterRoleBinding() (operatorServiceAccountClusterRoleBinding *rbac.ClusterRoleBinding, err error) {
fileLocation, err := filepath.Abs("deploy/cluster_role_binding.yaml")
if err != nil {
logrus.Fatalf("Failed to locate operator service account role binding yaml, %s", err)
}
file, err := ioutil.ReadFile(fileLocation)
if err != nil {
logrus.Errorf("Failed to locate operator service account role binding yaml, %s", err)
}
roleBinding := string(file)
decode := scheme.Codecs.UniversalDeserializer().Decode
object, _, err := decode([]byte(roleBinding), nil, nil)
if err != nil {
logrus.Errorf("Failed to deserialize yaml %s", err)
return nil, err
}
operatorServiceAccountClusterRoleBinding = object.(*rbac.ClusterRoleBinding)
return operatorServiceAccountClusterRoleBinding, nil
}

View File

@ -1,38 +0,0 @@
//
// 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
//
package main
import (
oauth "github.com/openshift/api/oauth/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func getOauthClient(name string) (oAuthClient *oauth.OAuthClient, err error) {
oAuthClient = &oauth.OAuthClient{}
err = oauthClientSet.restClient.Get().Name(name).Resource("oauthclients").Do().Into(oAuthClient)
if err != nil && errors.IsNotFound(err) {
return nil, err
}
return oAuthClient, nil
}
func getConfigMap(cmName string) (cm *corev1.ConfigMap, err error) {
cm, err = client.clientset.CoreV1().ConfigMaps(namespace).Get(cmName, metav1.GetOptions{})
if err != nil {
return nil, err
}
return cm, nil
}

View File

@ -1,45 +0,0 @@
//
// 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
//
package main
import (
"encoding/json"
"github.com/sirupsen/logrus"
api "k8s.io/apimachinery/pkg/types"
)
func patchCustomResource(path string, value bool) (err error) {
type PatchSpec struct {
Operation string `json:"op"`
Path string `json:"path"`
Value bool `json:"value"`
}
fields := make([]PatchSpec, 1)
fields[0].Operation = "replace"
fields[0].Path = path
fields[0].Value = value
patchBytes, err := json.Marshal(fields)
if err != nil {
logrus.Errorf("Failed to marchall fields %s", err)
return err
}
_, err = clientSet.restClient.Patch(api.JSONPatchType).Name(crName).Namespace(namespace).Resource(kind).Body(patchBytes).Do().Get()
if err != nil {
logrus.Errorf("Failed to patch CR: %s", err)
return err
}
return nil
}

View File

@ -1,96 +0,0 @@
#!/bin/bash
#
# Copyright (c) 2012-2020 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
# Exit on error
set -e
trap 'Catch_Finish $?' EXIT SIGINT
source ../.ci/util/ci_common.sh
Catch_Finish() {
rm -rf ${OPERATOR_REPO}/tmp
}
#TODO! Move this utilities to another folder
printInfo() {
green=`tput setaf 2`
reset=`tput sgr0`
echo "${green}[INFO]: ${1} ${reset}"
}
printError() {
red=`tput setaf 1`
reset=`tput sgr0`
echo "${red}[ERROR]: ${1} ${reset}"
}
init() {
MSFT_RELEASE="1.34.2"
GO_TOOLSET_VERSION="1.11.5-3"
SCRIPT=$(readlink -f "$0") # this script's absolute path
SCRIPTPATH=$(dirname "$SCRIPT") # /path/to/e2e/ folder
if [[ ${WORKSPACE} ]] && [[ -d ${WORKSPACE} ]]; then OPERATOR_REPO=${WORKSPACE}; else OPERATOR_REPO=$(dirname "$SCRIPTPATH"); fi
}
eval_minishift_env() {
if ! [ -x "$(command -v minsishift)" ]; then
printError 'Minishift is not installed.Please install minishift following the instructions: https://docs.okd.io/latest/minishift/getting-started/installing.html' >&2
exit 1
fi
if [[ ! $(ps axf | grep minishift | grep -v grep) ]]; then
printError "Minishift is not running. Please start minishift to be available to run e2e tests!"
exit 1
fi
eval $(minishift oc-env)
oc login -u system:admin
oc adm policy add-cluster-role-to-user cluster-admin developer && oc login -u developer -p developer
}
oc_tls_mode() {
# generate self signed cert
printInfo "Generate self signed certificate"
cd $OPERATOR_REPO/tmp && generate_self_signed_certs # replace default router cert
printInfo "Update OpenShift router tls secret"
oc project default
oc secrets new router-certs tls.crt=ca.crt tls.key=key.pem -o json --type='kubernetes.io/tls' --confirm | oc replace -f -
printInfo "Initiate a new router deployment"
sleep 20
oc rollout latest dc/router -n=default || true
}
run_tests() {
if [ ! -d "$OPERATOR_REPO/tmp" ]; then mkdir -p "$OPERATOR_REPO/tmp" && chmod 777 "$OPERATOR_REPO/tmp"; fi
eval_minishift_env
printInfo "Register a custom resource definition"
oc apply -f ${OPERATOR_REPO}/deploy/crds/org_v1_che_crd.yaml
oc_tls_mode
printInfo "Compile tests binary"
docker run -t \
-v ${OPERATOR_REPO}/tmp:/operator \
-v ${OPERATOR_REPO}:/opt/app-root/src/go/src/github.com/eclipse-che/che-operator registry.access.redhat.com/devtools/go-toolset-rhel7:${GO_TOOLSET_VERSION} \
sh -c "OOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o /operator/run-tests /opt/app-root/src/go/src/github.com/eclipse-che/che-operator/e2e/*.go"
printInfo "Build operator docker image and load in to minishift VM..."
cd ${OPERATOR_REPO} && docker build -t che/operator -f Dockerfile . && docker save che/operator > operator.tar
eval $(minishift docker-env) && docker load -i operator.tar && rm operator.tar
printInfo "Run tests..."
${OPERATOR_REPO}/tmp/run-tests
}
init
run_tests
#TODO avoid the use of cd on shell...

View File

@ -1,173 +0,0 @@
//
// 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
//
package main
import (
"log"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
"github.com/eclipse-che/che-operator/pkg/controller/che"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/clientcmd/api"
)
var (
crName = "eclipse-che"
kind = "checlusters"
groupName = "org.eclipse.che"
namespace = "che"
)
func main() {
logrus.Info("Starting CHE/CRW operator e2e tests")
logrus.Info("A running OCP instance and cluster-admin login are required")
logrus.Info("Adding CRD to schema")
if err := orgv1.SchemeBuilder.AddToScheme(scheme.Scheme); err != nil {
logrus.Fatalf("Failed to add CRD to scheme")
}
apiScheme := runtime.NewScheme()
if err := api.AddToScheme(apiScheme); err != nil {
logrus.Fatalf("Failed to add CRD to scheme")
}
logrus.Info("CRD successfully added to schema")
logrus.Infof("Creating a new namespace: %s", namespace)
ns := newNamespace()
if err := createNamespace(ns); err != nil {
logrus.Warn(err)
}
logrus.Info("Creating a new CR")
err = createCR()
if err != nil {
logrus.Fatalf("Failed to create %s CR: %s", crName, err)
}
logrus.Info("CR has been successfully created")
logrus.Infof("Getting CR %s to verify it has been successfully created", crName)
cheCluster, err := getCR()
if err != nil {
logrus.Fatalf("An error occurred: %s", err)
}
logrus.Infof("CR found: name: %s", cheCluster.Name)
logrus.Info("Creating a service account for operator deployment")
operatorServiceAccount, err := deserializeOperatorServiceAccount()
if err := createOperatorServiceAccount(operatorServiceAccount); err != nil {
logrus.Fatalf("Failed to create Operator service account: %s", err)
}
logrus.Info("Creating role for operator service account")
operatorServiceAccountRole, err := deserializeOperatorRole()
if err := createOperatorServiceAccountRole(operatorServiceAccountRole); err != nil {
logrus.Fatalf("Failed to create Operator service account role: %s", err)
}
logrus.Info("Creating RoleBinding")
operatorServiceAccountRoleBinding, err := deserializeOperatorRoleBinding()
if err := createOperatorServiceAccountRoleBinding(operatorServiceAccountRoleBinding); err != nil {
logrus.Fatalf("Failed to create Operator service account role binding: %s", err)
}
logrus.Info("Deploying operator")
operatorDeployment, err := deserializeOperatorDeployment()
if err := deployOperator(operatorDeployment); err != nil {
logrus.Fatalf("Failed to create Operator deployment: %s", err)
}
logrus.Info("Waiting for CR Available status. Timeout 15 min")
deployed, err := VerifyCheRunning(che.AvailableStatus)
if deployed {
logrus.Info("Installation succeeded")
}
// create clusterRole and clusterRoleBinding to let operator service account create oAuthclients
logrus.Info("Creating cluster role for operator service account")
operatorServiceAccountClusterRole, err := deserializeOperatorClusterRole()
if err := createOperatorServiceAccountClusterRole(operatorServiceAccountClusterRole); err != nil {
logrus.Fatalf("Failed to create Operator service account cluster role: %s", err)
}
logrus.Info("Creating RoleBinding")
operatorServiceAccountClusterRoleBinding, err := deserializeOperatorClusterRoleBinding()
if err := createOperatorServiceAccountClusterRoleBinding(operatorServiceAccountClusterRoleBinding); err != nil {
logrus.Fatalf("Failed to create Operator service account cluster role binding: %s", err)
}
// reconfigure CR to enable login with OpenShift
logrus.Info("Patching CR with oAuth enabled. This should cause a new Che deployment")
patchPath := "/spec/auth/openShiftoAuth"
if err := patchCustomResource(patchPath, true); err != nil {
logrus.Fatalf("An error occurred while patching CR %s", err)
}
// check if a CR status has changed to Rolling update in progress
redeployed, err := VerifyCheRunning(che.RollingUpdateInProgressStatus)
if redeployed {
logrus.Info("New deployment triggered")
}
// wait for Available status
logrus.Info("Waiting for CR Available status. Timeout 15 min")
deployed, err = VerifyCheRunning(che.AvailableStatus)
if deployed {
logrus.Info("Installation succeeded")
}
// check if oAuthClient has been created
cr, err := getCR()
if err != nil {
logrus.Fatalf("Failed to get CR: %s", err)
}
oAuthClientName := cr.Spec.Auth.OAuthClientName
_, err = getOauthClient(oAuthClientName)
if err != nil {
logrus.Fatalf("oAuthclient %s not found", oAuthClientName)
}
logrus.Infof("Checking if oauthclient %s has been created", oAuthClientName)
// verify oAuthClient name is set in che ConfigMap
cm, err := getConfigMap("che")
if err != nil {
log.Fatalf("Failed to get ConfigMap: %s", err)
}
expectedIdentityProvider := "openshift-v3"
actualIdentityProvider := cm.Data["CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"]
expectedWorkspaceProject := ""
actualWorkspaceProject := cm.Data["CHE_INFRA_OPENSHIFT_PROJECT"]
logrus.Info("Checking if identity provider is added to configmap")
if expectedIdentityProvider != actualIdentityProvider {
logrus.Fatalf("Test failed. Expecting identity provider: %s, got: %s", expectedIdentityProvider, actualIdentityProvider)
}
logrus.Info("Checking if workspace project is empty in CM")
if expectedWorkspaceProject != actualWorkspaceProject {
logrus.Fatalf("Test failed. Expecting identity provider: %s, got: %s", expectedWorkspaceProject, actualWorkspaceProject)
}
// cleanup
logrus.Infof("Tests passed. Deleting namespace %s", namespace)
if err := deleteNamespace(); err != nil {
logrus.Errorf("Failed to delete namespace %s: %s", namespace, err)
}
}

View File

@ -1,36 +0,0 @@
//
// 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
//
package main
import (
"errors"
"time"
)
func VerifyCheRunning(status string) (deployed bool, err error) {
timeout := time.After(15 * time.Minute)
tick := time.Tick(10 * time.Second)
for {
select {
case <-timeout:
return false, errors.New("timed out")
case <-tick:
customResource, _ := getCR()
if customResource.Status.CheClusterRunning != status {
} else {
return true, nil
}
}
}
}

View File

@ -409,8 +409,9 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
if instance.Spec.Auth.InitialOpenShiftOAuthUser == nil && instance.Status.OpenShiftOAuthUserCredentialsSecret != "" {
secret, err := deploy.GetSecret(deployContext, openShiftOAuthUserCredentialsSecret, instance.Namespace)
if secret == nil {
secret := &corev1.Secret{}
exists, err := deploy.GetNamespacedObject(deployContext, openShiftOAuthUserCredentialsSecret, secret)
if !exists {
if err == nil {
instance.Status.OpenShiftOAuthUserCredentialsSecret = ""
if err := r.UpdateCheCRStatus(instance, "openShiftOAuthUserCredentialsSecret", ""); err != nil {
@ -604,15 +605,12 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
// Create service account "che" for che-server component.
// "che" is the one which token is used to create workspace objects.
// Notice: Also we have on more "che-workspace" SA used by plugins like exec, terminal, metrics with limited privileges.
cheSA, err := deploy.SyncServiceAccountToCluster(deployContext, CheServiceAccountName)
if cheSA == nil {
logrus.Info("Waiting on service account 'che' to be created")
done, err = deploy.SyncServiceAccountToCluster(deployContext, CheServiceAccountName)
if !done {
if err != nil {
logrus.Error(err)
}
if !tests {
return reconcile.Result{RequeueAfter: time.Second}, err
}
return reconcile.Result{RequeueAfter: time.Second}, err
}
if !util.IsOAuthEnabled(instance) && !util.IsWorkspaceInSameNamespaceWithChe(instance) {
@ -711,14 +709,6 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
return reconcile.Result{}, err
}
done, err = deploy.DeleteNamespacedObject(deployContext, deploy.DefaultPostgresVolumeClaimName, &corev1.PersistentVolumeClaim{})
if !done {
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
} else {
done, err := deploy.DeleteNamespacedObject(deployContext, deploy.DefaultCheVolumeClaimName, &corev1.PersistentVolumeClaim{})
if !done {
@ -729,96 +719,13 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
// Create Postgres resources and provisioning unless an external DB is used
externalDB := instance.Spec.Database.ExternalDb
if !externalDB {
if cheMultiUser == "false" {
done, err := deploy.Delete(deployContext, types.NamespacedName{Name: deploy.PostgresName, Namespace: instance.Namespace}, &appsv1.Deployment{})
if !tests {
if !done {
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
}
} else {
// Create a new postgres service
serviceStatus := deploy.SyncServiceToCluster(deployContext, deploy.PostgresName, []string{deploy.PostgresName}, []int32{5432}, deploy.PostgresName)
if !tests {
if !serviceStatus.Continue {
logrus.Info("Waiting on service 'postgres' to be ready")
if serviceStatus.Err != nil {
logrus.Error(serviceStatus.Err)
}
return reconcile.Result{Requeue: serviceStatus.Requeue}, serviceStatus.Err
}
}
// Create a new Postgres PVC object
done, err := deploy.SyncPVCToCluster(deployContext, deploy.DefaultPostgresVolumeClaimName, "1Gi", deploy.PostgresName)
if !tests {
if !done {
logrus.Infof("Waiting on pvc '%s' to be bound. Sometimes PVC can be bound only when the first consumer is created.", deploy.DefaultPostgresVolumeClaimName)
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
}
// Create a new Postgres deployment
provisioned, err := postgres.SyncPostgresDeploymentToCluster(deployContext)
if !tests {
if !provisioned {
logrus.Infof("Waiting on deployment '%s' to be ready", deploy.PostgresName)
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
}
if !tests {
identityProviderPostgresPassword := instance.Spec.Auth.IdentityProviderPostgresPassword
identityProviderPostgresSecret := instance.Spec.Auth.IdentityProviderPostgresSecret
if len(identityProviderPostgresSecret) > 0 {
_, password, err := util.K8sclient.ReadSecret(identityProviderPostgresSecret, instance.Namespace)
if err != nil {
logrus.Errorf("Failed to read '%s' secret: %s", identityProviderPostgresSecret, err)
return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, err
}
identityProviderPostgresPassword = password
}
dbStatus := instance.Status.DbProvisoned
// provision Db and users for Che and Keycloak servers
if !dbStatus {
_, err := util.K8sclient.ExecIntoPod(
instance,
deploy.PostgresName,
func(cr *orgv1.CheCluster) (string, error) {
return identity_provider.GetPostgresProvisionCommand(identityProviderPostgresPassword), nil
},
"create Keycloak DB, user, privileges")
if err == nil {
for {
instance.Status.DbProvisoned = true
if err := r.UpdateCheCRStatus(instance, "status: provisioned with DB and user", "true"); err != nil &&
errors.IsConflict(err) {
instance, _ = r.GetCR(request)
continue
}
break
}
} else {
return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, err
}
}
}
postgres := postgres.NewPostgres(deployContext)
done, err = postgres.Sync()
if !done {
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
tlsSupport := instance.Spec.Server.TlsSupport
@ -828,16 +735,13 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
// create Che service and route
serviceStatus := server.SyncCheServiceToCluster(deployContext)
if !tests {
if !serviceStatus.Continue {
logrus.Infof("Waiting on service '%s' to be ready", deploy.CheServiceName)
if serviceStatus.Err != nil {
logrus.Error(serviceStatus.Err)
}
return reconcile.Result{Requeue: serviceStatus.Requeue}, serviceStatus.Err
done, err = server.SyncCheServiceToCluster(deployContext)
if !done {
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
deployContext.InternalService.CheHost = fmt.Sprintf("http://%s.%s.svc:8080", deploy.CheServiceName, deployContext.CheCluster.Namespace)
@ -878,7 +782,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
customHost = ""
}
route, err := deploy.SyncRouteToCluster(
done, err := deploy.SyncRouteToCluster(
deployContext,
cheFlavor,
customHost,
@ -886,13 +790,20 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
8080,
deployContext.CheCluster.Spec.Server.CheServerRoute,
cheFlavor)
if route == nil {
logrus.Infof("Waiting on route '%s' to be ready", cheFlavor)
if !done {
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
return reconcile.Result{RequeueAfter: time.Second * 1}, err
route := &routev1.Route{}
exists, err := deploy.GetNamespacedObject(deployContext, cheFlavor, route)
if !exists {
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
cheHost = route.Spec.Host
if customHost == "" {
@ -1055,7 +966,7 @@ func EvaluateCheServerVersion(cr *orgv1.CheCluster) string {
func getDefaultCheHost(deployContext *deploy.DeployContext) (string, error) {
cheFlavor := deploy.DefaultCheFlavor(deployContext.CheCluster)
route, err := deploy.SyncRouteToCluster(
done, err := deploy.SyncRouteToCluster(
deployContext,
cheFlavor,
"",
@ -1063,13 +974,22 @@ func getDefaultCheHost(deployContext *deploy.DeployContext) (string, error) {
8080,
deployContext.CheCluster.Spec.Server.CheServerRoute,
cheFlavor)
if route == nil {
logrus.Infof("Waiting on route '%s' to be ready", cheFlavor)
if !done {
if err != nil {
logrus.Error(err)
}
return "", err
}
route := &routev1.Route{}
exists, err := deploy.GetNamespacedObject(deployContext, cheFlavor, route)
if !exists {
if err != nil {
logrus.Error(err)
}
return "", err
}
return route.Spec.Host, nil
}

View File

@ -34,7 +34,7 @@ func (r *ReconcileChe) GenerateAndSaveFields(deployContext *deploy.DeployContext
if len(deployContext.CheCluster.Spec.Database.ChePostgresSecret) < 1 {
if len(deployContext.CheCluster.Spec.Database.ChePostgresUser) < 1 || len(deployContext.CheCluster.Spec.Database.ChePostgresPassword) < 1 {
chePostgresSecret := deploy.DefaultChePostgresSecret()
_, err := deploy.SyncSecret(deployContext, chePostgresSecret, cheNamespace, map[string][]byte{"user": []byte(deploy.DefaultChePostgresUser), "password": []byte(util.GeneratePasswd(12))})
_, err := deploy.SyncSecretToCluster(deployContext, chePostgresSecret, cheNamespace, map[string][]byte{"user": []byte(deploy.DefaultChePostgresUser), "password": []byte(util.GeneratePasswd(12))})
if err != nil {
return err
}
@ -70,7 +70,7 @@ func (r *ReconcileChe) GenerateAndSaveFields(deployContext *deploy.DeployContext
if len(deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresPassword) < 1 {
identityPostgresSecret := deploy.DefaultCheIdentityPostgresSecret()
_, err := deploy.SyncSecret(deployContext, identityPostgresSecret, cheNamespace, map[string][]byte{"password": []byte(keycloakPostgresPassword)})
_, err := deploy.SyncSecretToCluster(deployContext, identityPostgresSecret, cheNamespace, map[string][]byte{"password": []byte(keycloakPostgresPassword)})
if err != nil {
return err
}
@ -94,7 +94,7 @@ func (r *ReconcileChe) GenerateAndSaveFields(deployContext *deploy.DeployContext
if len(deployContext.CheCluster.Spec.Auth.IdentityProviderAdminUserName) < 1 || len(deployContext.CheCluster.Spec.Auth.IdentityProviderPassword) < 1 {
identityProviderSecret := deploy.DefaultCheIdentitySecret()
_, err = deploy.SyncSecret(deployContext, identityProviderSecret, cheNamespace, map[string][]byte{"user": []byte(keycloakAdminUserName), "password": []byte(keycloakAdminPassword)})
_, err = deploy.SyncSecretToCluster(deployContext, identityProviderSecret, cheNamespace, map[string][]byte{"user": []byte(keycloakAdminUserName), "password": []byte(keycloakAdminPassword)})
if err != nil {
return err
}

View File

@ -23,6 +23,7 @@ import (
oauthv1 "github.com/openshift/api/config/v1"
userv1 "github.com/openshift/api/user/v1"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@ -79,8 +80,14 @@ func (iuh *OpenShiftOAuthUserOperatorHandler) SyncOAuthInitialUser(openshiftOAut
}
initialUserSecretData := map[string][]byte{"user": []byte(userName), "password": []byte(password)}
credentionalSecret, err := deploy.SyncSecret(deployContext, openShiftOAuthUserCredentialsSecret, cr.Namespace, initialUserSecretData)
if credentionalSecret == nil {
done, err := deploy.SyncSecretToCluster(deployContext, openShiftOAuthUserCredentialsSecret, cr.Namespace, initialUserSecretData)
if !done {
return false, err
}
credentionalSecret := &corev1.Secret{}
exists, err := deploy.GetNamespacedObject(deployContext, openShiftOAuthUserCredentialsSecret, credentionalSecret)
if !exists {
return false, err
}
@ -93,8 +100,8 @@ func (iuh *OpenShiftOAuthUserOperatorHandler) SyncOAuthInitialUser(openshiftOAut
}
htpasswdFileSecretData := map[string][]byte{"htpasswd": []byte(htpasswdFileContent)}
secret, err := deploy.SyncSecret(deployContext, htpasswdSecretName, ocConfigNamespace, htpasswdFileSecretData)
if secret == nil {
done, err = deploy.SyncSecretToCluster(deployContext, htpasswdSecretName, ocConfigNamespace, htpasswdFileSecretData)
if !done {
return false, err
}
@ -127,11 +134,13 @@ func (iuh *OpenShiftOAuthUserOperatorHandler) DeleteOAuthInitialUser(deployConte
return err
}
if err := deploy.DeleteSecret(htpasswdSecretName, ocConfigNamespace, iuh.runtimeClient); err != nil {
_, err = deploy.Delete(deployContext, types.NamespacedName{Name: htpasswdSecretName, Namespace: ocConfigNamespace}, &corev1.Secret{})
if err != nil {
return err
}
if err := deploy.DeleteSecret(openShiftOAuthUserCredentialsSecret, cr.Namespace, iuh.runtimeClient); err != nil {
_, err = deploy.DeleteNamespacedObject(deployContext, openShiftOAuthUserCredentialsSecret, &corev1.Secret{})
if err != nil {
return err
}

View File

@ -47,8 +47,8 @@ const (
func (r *ReconcileChe) delegateWorkspacePermissionsInTheSameNamespaceWithChe(deployContext *deploy.DeployContext) (reconcile.Result, error) {
// Create "che-workspace" service account.
// Che workspace components use this service account.
cheWorkspaceSA, err := deploy.SyncServiceAccountToCluster(deployContext, CheWorkspacesServiceAccount)
if cheWorkspaceSA == nil {
done, err := deploy.SyncServiceAccountToCluster(deployContext, CheWorkspacesServiceAccount)
if !done {
logrus.Infof("Waiting on service account '%s' to be created", CheWorkspacesServiceAccount)
if err != nil {
logrus.Error(err)
@ -58,7 +58,7 @@ func (r *ReconcileChe) delegateWorkspacePermissionsInTheSameNamespaceWithChe(dep
// Create view role for "che-workspace" service account.
// This role used by exec terminals, tasks, metric che-theia plugin and so on.
done, err := deploy.SyncViewRoleToCluster(deployContext)
done, err = deploy.SyncViewRoleToCluster(deployContext)
if !done {
logrus.Infof("Waiting on role '%s' to be created", deploy.ViewRoleName)
if err != nil {

View File

@ -63,3 +63,7 @@ type Proxy struct {
NoProxy string
TrustedCAMapName string
}
type Syncable interface {
Sync() (bool, error)
}

View File

@ -125,10 +125,11 @@ func MountSecrets(specDeployment *appsv1.Deployment, deployContext *DeployContex
container.VolumeMounts = append(container.VolumeMounts, volumeMount)
case "env":
secret, err := GetSecret(deployContext, secretObj.Name, deployContext.CheCluster.Namespace)
secret := &corev1.Secret{}
exists, err := GetNamespacedObject(deployContext, secretObj.Name, secret)
if err != nil {
return err
} else if secret == nil {
} else if !exists {
return fmt.Errorf("Secret '%s' not found", secretObj.Name)
}

View File

@ -60,15 +60,13 @@ func SyncDevfileRegistryToCluster(deployContext *deploy.DeployContext, cheHost s
}
// Create a new registry service
serviceStatus := deploy.SyncServiceToCluster(deployContext, deploy.DevfileRegistryName, []string{"http"}, []int32{8080}, deploy.DevfileRegistryName)
done, err = deploy.SyncServiceToCluster(deployContext, deploy.DevfileRegistryName, []string{"http"}, []int32{8080}, deploy.DevfileRegistryName)
if !util.IsTestMode() {
if !serviceStatus.Continue {
logrus.Info("Waiting on service '" + deploy.DevfileRegistryName + "' to be ready")
if serviceStatus.Err != nil {
logrus.Error(serviceStatus.Err)
if !done {
if err != nil {
logrus.Error(err)
}
return false, serviceStatus.Err
return false, err
}
}

View File

@ -16,6 +16,7 @@ import (
"github.com/eclipse-che/che-operator/pkg/deploy"
"github.com/eclipse-che/che-operator/pkg/deploy/gateway"
"github.com/eclipse-che/che-operator/pkg/util"
routev1 "github.com/openshift/api/route/v1"
"github.com/sirupsen/logrus"
extentionsv1beta1 "k8s.io/api/extensions/v1beta1"
)
@ -96,14 +97,15 @@ func Expose(
}
return "", false, err
}
if err := deploy.DeleteRouteIfExists(endpointName, deployContext); !util.IsTestMode() && err != nil {
_, err = deploy.DeleteNamespacedObject(deployContext, endpointName, &routev1.Route{})
if err != nil {
logrus.Error(err)
}
} else {
// the empty string for a host is intentional here - we let OpenShift decide on the hostname
route, err := deploy.SyncRouteToCluster(deployContext, endpointName, "", endpointName, 8080, routeCustomSettings, component)
if route == nil {
logrus.Infof("Waiting on route '%s' to be ready", endpointName)
done, err := deploy.SyncRouteToCluster(deployContext, endpointName, "", endpointName, 8080, routeCustomSettings, component)
if !done {
if err != nil {
logrus.Error(err)
}
@ -114,6 +116,15 @@ func Expose(
logrus.Error(err)
}
route := &routev1.Route{}
exists, err := deploy.GetNamespacedObject(deployContext, endpointName, route)
if !exists {
if err != nil {
logrus.Error(err)
}
return "", false, err
}
endpoint = route.Spec.Host
}
}

View File

@ -64,14 +64,12 @@ func SyncIdentityProviderToCluster(deployContext *deploy.DeployContext) (bool, e
}
func syncService(deployContext *deploy.DeployContext) (bool, error) {
serviceStatus := deploy.SyncServiceToCluster(
return deploy.SyncServiceToCluster(
deployContext,
deploy.IdentityProviderName,
[]string{"http"},
[]int32{8080},
deploy.IdentityProviderName)
return serviceStatus.Continue, serviceStatus.Err
}
func syncExposure(deployContext *deploy.DeployContext) (bool, error) {
@ -165,7 +163,7 @@ func SyncOpenShiftIdentityProviderItems(deployContext *deploy.DeployContext) (bo
keycloakURL := cr.Spec.Auth.IdentityProviderURL
cheFlavor := deploy.DefaultCheFlavor(cr)
keycloakRealm := util.GetValue(cr.Spec.Auth.IdentityProviderRealm, cheFlavor)
oAuthClient := deploy.NewOAuthClient(oAuthClientName, oauthSecret, keycloakURL, keycloakRealm, util.IsOpenShift4)
oAuthClient := deploy.GetOAuthClientSpec(oAuthClientName, oauthSecret, keycloakURL, keycloakRealm, util.IsOpenShift4)
provisioned, err := deploy.Sync(deployContext, oAuthClient, oAuthClientDiffOpts)
if !provisioned {
return false, err

View File

@ -23,7 +23,7 @@ const (
OAuthFinalizerName = "oauthclients.finalizers.che.eclipse.org"
)
func NewOAuthClient(name string, oauthSecret string, keycloakURL string, keycloakRealm string, isOpenShift4 bool) *oauth.OAuthClient {
func GetOAuthClientSpec(name string, oauthSecret string, keycloakURL string, keycloakRealm string, isOpenShift4 bool) *oauth.OAuthClient {
providerName := "openshift-v3"
if isOpenShift4 {
providerName = "openshift-v4"

View File

@ -62,16 +62,12 @@ func SyncPluginRegistryToCluster(deployContext *deploy.DeployContext, cheHost st
}
// Create a new registry service
serviceStatus := deploy.SyncServiceToCluster(deployContext, deploy.PluginRegistryName, []string{"http"}, []int32{8080}, deploy.PluginRegistryName)
if !util.IsTestMode() {
if !serviceStatus.Continue {
logrus.Info("Waiting on service '" + deploy.PluginRegistryName + "' to be ready")
if serviceStatus.Err != nil {
logrus.Error(serviceStatus.Err)
}
return false, serviceStatus.Err
done, err = deploy.SyncServiceToCluster(deployContext, deploy.PluginRegistryName, []string{"http"}, []int32{8080}, deploy.PluginRegistryName)
if !done {
if err != nil {
logrus.Error(err)
}
return false, err
}
deployContext.InternalService.PluginRegistryHost = fmt.Sprintf("http://%s.%s.svc:8080/v3", deploy.PluginRegistryName, deployContext.CheCluster.Namespace)

View File

@ -12,8 +12,13 @@
package postgres
import (
"fmt"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
"github.com/eclipse-che/che-operator/pkg/deploy"
identity_provider "github.com/eclipse-che/che-operator/pkg/deploy/identity-provider"
"github.com/eclipse-che/che-operator/pkg/util"
"github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -24,9 +29,76 @@ var (
postgresAdminPassword = util.GeneratePasswd(12)
)
func SyncPostgresDeploymentToCluster(deployContext *deploy.DeployContext) (bool, error) {
type Postgres struct {
deployContext *deploy.DeployContext
isMultiUser bool
}
func NewPostgres(deployContext *deploy.DeployContext) *Postgres {
return &Postgres{
deployContext: deployContext,
isMultiUser: deploy.GetCheMultiUser(deployContext.CheCluster) == "true",
}
}
func (p *Postgres) Sync() (bool, error) {
if p.deployContext.CheCluster.Spec.Database.ExternalDb {
return true, nil
}
done, err := p.syncService()
if !done {
return false, err
}
done, err = p.syncPVC()
if !done {
return false, err
}
done, err = p.syncDeployment()
if !done {
return false, err
}
if !p.deployContext.CheCluster.Status.DbProvisoned {
if !util.IsTestMode() { // ignore in tests
done, err = p.provisionDB()
if !done {
return false, err
}
}
}
return true, nil
}
func (p *Postgres) syncService() (bool, error) {
if !p.isMultiUser {
return deploy.DeleteNamespacedObject(p.deployContext, deploy.PostgresName, &corev1.Service{})
}
return deploy.SyncServiceToCluster(p.deployContext, deploy.PostgresName, []string{deploy.PostgresName}, []int32{5432}, deploy.PostgresName)
}
func (p *Postgres) syncPVC() (bool, error) {
if !p.isMultiUser {
return deploy.DeleteNamespacedObject(p.deployContext, deploy.DefaultPostgresVolumeClaimName, &corev1.PersistentVolumeClaim{})
}
done, err := deploy.SyncPVCToCluster(p.deployContext, deploy.DefaultPostgresVolumeClaimName, "1Gi", deploy.PostgresName)
if !done {
logrus.Infof("Waiting on pvc '%s' to be bound. Sometimes PVC can be bound only when the first consumer is created.", deploy.DefaultPostgresVolumeClaimName)
}
return done, err
}
func (p *Postgres) syncDeployment() (bool, error) {
if !p.isMultiUser {
return deploy.DeleteNamespacedObject(p.deployContext, deploy.PostgresName, &appsv1.Deployment{})
}
clusterDeployment := &appsv1.Deployment{}
exists, err := deploy.GetNamespacedObject(deployContext, deploy.PostgresName, clusterDeployment)
exists, err := deploy.GetNamespacedObject(p.deployContext, deploy.PostgresName, clusterDeployment)
if err != nil {
return false, err
}
@ -35,25 +107,54 @@ func SyncPostgresDeploymentToCluster(deployContext *deploy.DeployContext) (bool,
clusterDeployment = nil
}
specDeployment, err := GetSpecPostgresDeployment(deployContext, clusterDeployment)
specDeployment, err := p.getDeploymentSpec(clusterDeployment)
if err != nil {
return false, err
}
return deploy.SyncDeploymentSpecToCluster(deployContext, specDeployment, deploy.DefaultDeploymentDiffOpts)
return deploy.SyncDeploymentSpecToCluster(p.deployContext, specDeployment, deploy.DefaultDeploymentDiffOpts)
}
func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeployment *appsv1.Deployment) (*appsv1.Deployment, error) {
isOpenShift, _, err := util.DetectOpenShift()
if err != nil {
return nil, err
func (p *Postgres) provisionDB() (bool, error) {
identityProviderPostgresPassword := p.deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresPassword
identityProviderPostgresSecret := p.deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresSecret
if identityProviderPostgresSecret != "" {
secret := &corev1.Secret{}
exists, err := deploy.GetNamespacedObject(p.deployContext, identityProviderPostgresSecret, secret)
if err != nil {
return false, err
} else if !exists {
return false, fmt.Errorf("Secret '%s' not found", identityProviderPostgresSecret)
}
identityProviderPostgresPassword = string(secret.Data["password"])
}
_, err := util.K8sclient.ExecIntoPod(
p.deployContext.CheCluster,
deploy.PostgresName,
func(cr *orgv1.CheCluster) (string, error) {
return identity_provider.GetPostgresProvisionCommand(identityProviderPostgresPassword), nil
},
"create Keycloak DB, user, privileges")
if err != nil {
return false, err
}
p.deployContext.CheCluster.Status.DbProvisoned = true
err = deploy.UpdateCheCRStatus(p.deployContext, "status: provisioned with DB and user", "true")
if err != nil {
return false, err
}
return true, nil
}
func (p *Postgres) getDeploymentSpec(clusterDeployment *appsv1.Deployment) (*appsv1.Deployment, error) {
terminationGracePeriodSeconds := int64(30)
labels, labelSelector := deploy.GetLabelsAndSelector(deployContext.CheCluster, deploy.PostgresName)
chePostgresDb := util.GetValue(deployContext.CheCluster.Spec.Database.ChePostgresDb, "dbche")
postgresImage := util.GetValue(deployContext.CheCluster.Spec.Database.PostgresImage, deploy.DefaultPostgresImage(deployContext.CheCluster))
pullPolicy := corev1.PullPolicy(util.GetValue(string(deployContext.CheCluster.Spec.Database.PostgresImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(postgresImage)))
labels, labelSelector := deploy.GetLabelsAndSelector(p.deployContext.CheCluster, deploy.PostgresName)
chePostgresDb := util.GetValue(p.deployContext.CheCluster.Spec.Database.ChePostgresDb, "dbche")
postgresImage := util.GetValue(p.deployContext.CheCluster.Spec.Database.PostgresImage, deploy.DefaultPostgresImage(p.deployContext.CheCluster))
pullPolicy := corev1.PullPolicy(util.GetValue(string(p.deployContext.CheCluster.Spec.Database.PostgresImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(postgresImage)))
if clusterDeployment != nil {
clusterContainer := &clusterDeployment.Spec.Template.Spec.Containers[0]
@ -70,7 +171,7 @@ func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeplo
},
ObjectMeta: metav1.ObjectMeta{
Name: deploy.PostgresName,
Namespace: deployContext.CheCluster.Namespace,
Namespace: p.deployContext.CheCluster.Namespace,
Labels: labels,
},
Spec: appsv1.DeploymentSpec{
@ -108,18 +209,18 @@ func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeplo
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Memory,
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Memory,
deploy.DefaultPostgresMemoryRequest),
corev1.ResourceCPU: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Cpu,
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Cpu,
deploy.DefaultPostgresCpuRequest),
},
Limits: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Memory,
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Memory,
deploy.DefaultPostgresMemoryLimit),
corev1.ResourceCPU: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Cpu,
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Cpu,
deploy.DefaultPostgresCpuLimit),
},
},
@ -183,7 +284,7 @@ func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeplo
container := &deployment.Spec.Template.Spec.Containers[0]
chePostgresSecret := deployContext.CheCluster.Spec.Database.ChePostgresSecret
chePostgresSecret := p.deployContext.CheCluster.Spec.Database.ChePostgresSecret
if len(chePostgresSecret) > 0 {
container.Env = append(container.Env,
corev1.EnvVar{
@ -211,14 +312,14 @@ func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeplo
container.Env = append(container.Env,
corev1.EnvVar{
Name: "POSTGRESQL_USER",
Value: deployContext.CheCluster.Spec.Database.ChePostgresUser,
Value: p.deployContext.CheCluster.Spec.Database.ChePostgresUser,
}, corev1.EnvVar{
Name: "POSTGRESQL_PASSWORD",
Value: deployContext.CheCluster.Spec.Database.ChePostgresPassword,
Value: p.deployContext.CheCluster.Spec.Database.ChePostgresPassword,
})
}
if !isOpenShift {
if !util.IsOpenShift {
var runAsUser int64 = 26
deployment.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{
RunAsUser: &runAsUser,

View File

@ -12,15 +12,19 @@
package postgres
import (
"context"
"os"
"github.com/eclipse-che/che-operator/pkg/util"
"github.com/eclipse-che/che-operator/pkg/deploy"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
@ -99,7 +103,8 @@ func TestDeployment(t *testing.T) {
Proxy: &deploy.Proxy{},
}
deployment, err := GetSpecPostgresDeployment(deployContext, nil)
postgres := NewPostgres(deployContext)
deployment, err := postgres.getDeploymentSpec(nil)
if err != nil {
t.Fatalf("Error creating deployment: %v", err)
}
@ -117,3 +122,46 @@ func TestDeployment(t *testing.T) {
})
}
}
func TestSyncPostgresToCluster(t *testing.T) {
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
corev1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &deploy.DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
},
ClusterAPI: deploy.ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
postgres := NewPostgres(deployContext)
done, err := postgres.Sync()
if !done || err != nil {
t.Fatalf("Failed to sync PostgreSQL: %v", err)
}
service := &corev1.Service{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: deploy.PostgresName, Namespace: "eclipse-che"}, service)
if err != nil {
t.Fatalf("Failed to get service: %v", err)
}
pvc := &corev1.PersistentVolumeClaim{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: deploy.DefaultPostgresVolumeClaimName, Namespace: "eclipse-che"}, pvc)
if err != nil {
t.Fatalf("Failed to get pvc: %v", err)
}
deployment := &appsv1.Deployment{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: deploy.PostgresName, Namespace: "eclipse-che"}, deployment)
if err != nil {
t.Fatalf("Failed to get deployment: %v", err)
}
}

View File

@ -20,14 +20,10 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
routev1 "github.com/openshift/api/route/v1"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
const (
@ -57,82 +53,21 @@ func SyncRouteToCluster(
serviceName string,
servicePort int32,
routeCustomSettings orgv1.RouteCustomSettings,
component string) (*routev1.Route, error) {
component string) (bool, error) {
specRoute, err := GetSpecRoute(deployContext, name, host, serviceName, servicePort, routeCustomSettings, component)
routeSpec, err := GetRouteSpec(deployContext, name, host, serviceName, servicePort, routeCustomSettings, component)
if err != nil {
return nil, err
return false, err
}
clusterRoute, err := GetClusterRoute(specRoute.Name, specRoute.Namespace, deployContext.ClusterAPI.Client)
if err != nil {
return nil, err
}
if clusterRoute == nil {
logrus.Infof("Creating a new object: %s, name %s", specRoute.Kind, specRoute.Name)
err := deployContext.ClusterAPI.Client.Create(context.TODO(), specRoute)
if !errors.IsAlreadyExists(err) {
return nil, err
}
return nil, nil
}
diffOpts := routeDiffOpts
if host != "" {
diffOpts = routeWithHostDiffOpts
return Sync(deployContext, routeSpec, routeWithHostDiffOpts)
}
diff := cmp.Diff(clusterRoute, specRoute, diffOpts)
if len(diff) > 0 {
logrus.Infof("Deleting existed object: %s, name: %s", clusterRoute.Kind, clusterRoute.Name)
fmt.Printf("Difference:\n%s", diff)
err := deployContext.ClusterAPI.Client.Delete(context.TODO(), clusterRoute)
if !errors.IsNotFound(err) {
return nil, err
}
return nil, nil
}
return clusterRoute, nil
return Sync(deployContext, routeSpec, routeDiffOpts)
}
func DeleteRouteIfExists(name string, deployContext *DeployContext) error {
ingress, err := GetClusterRoute(name, deployContext.CheCluster.Namespace, deployContext.ClusterAPI.Client)
if err != nil {
return err
}
if ingress != nil {
err = deployContext.ClusterAPI.Client.Delete(context.TODO(), ingress)
if !errors.IsNotFound(err) {
return err
}
}
return nil
}
// GetClusterRoute returns existing route.
func GetClusterRoute(name string, namespace string, client runtimeClient.Client) (*routev1.Route, error) {
route := &routev1.Route{}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := client.Get(context.TODO(), namespacedName, route)
if err != nil {
if errors.IsNotFound(err) {
return nil, nil
}
return nil, err
}
return route, nil
}
// GetSpecRoute returns default configuration of a route in Che namespace.
func GetSpecRoute(
// GetRouteSpec returns default configuration of a route in Che namespace.
func GetRouteSpec(
deployContext *DeployContext,
name string,
host string,
@ -201,10 +136,5 @@ func GetSpecRoute(
}
}
err := controllerutil.SetControllerReference(deployContext.CheCluster, route, deployContext.ClusterAPI.Scheme)
if err != nil {
return nil, err
}
return route, nil
}

View File

@ -12,6 +12,7 @@
package deploy
import (
"context"
"os"
"reflect"
@ -19,9 +20,9 @@ import (
routev1 "github.com/openshift/api/route/v1"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
"github.com/eclipse-che/che-operator/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
@ -75,14 +76,6 @@ func TestRouteSpec(t *testing.T) {
"app.kubernetes.io/managed-by": DefaultCheFlavor(cheCluster) + "-operator",
"app.kubernetes.io/name": DefaultCheFlavor(cheCluster),
},
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: "org.eclipse.che/v1",
Kind: "CheCluster",
Controller: util.NewBoolPointer(true),
BlockOwnerDeletion: util.NewBoolPointer(true),
},
},
},
TypeMeta: metav1.TypeMeta{
Kind: "Route",
@ -126,14 +119,6 @@ func TestRouteSpec(t *testing.T) {
"app.kubernetes.io/managed-by": DefaultCheFlavor(cheCluster) + "-operator",
"app.kubernetes.io/name": DefaultCheFlavor(cheCluster),
},
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: "org.eclipse.che/v1",
Kind: "CheCluster",
Controller: util.NewBoolPointer(true),
BlockOwnerDeletion: util.NewBoolPointer(true),
},
},
},
TypeMeta: metav1.TypeMeta{
Kind: "Route",
@ -172,7 +157,7 @@ func TestRouteSpec(t *testing.T) {
},
}
actualRoute, err := GetSpecRoute(deployContext,
actualRoute, err := GetRouteSpec(deployContext,
testCase.routeName,
testCase.routeHost,
testCase.serviceName,
@ -190,3 +175,60 @@ func TestRouteSpec(t *testing.T) {
})
}
}
func TestSyncRouteToCluster(t *testing.T) {
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
routev1.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
done, err := SyncRouteToCluster(deployContext, "test", "", "service", 80, orgv1.RouteCustomSettings{}, "test")
if !done || err != nil {
t.Fatalf("Failed to sync route: %v", err)
}
// sync another route
done, err = SyncRouteToCluster(deployContext, "test", "", "service", 90, orgv1.RouteCustomSettings{}, "test")
if !done || err != nil {
t.Fatalf("Failed to sync route: %v", err)
}
actual := &routev1.Route{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "test"}, actual)
if err != nil {
t.Fatalf("Failed to get route: %v", err)
}
if actual.Spec.Port.TargetPort.IntVal != 90 {
t.Fatalf("Failed to sync route: %v", err)
}
// sync route with labels & domain
done, err = SyncRouteToCluster(deployContext, "test", "", "service", 90, orgv1.RouteCustomSettings{Labels: "a=b", Domain: "domain"}, "test")
if !done || err != nil {
t.Fatalf("Failed to sync route: %v", err)
}
actual = &routev1.Route{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "test"}, actual)
if err != nil {
t.Fatalf("Failed to get route: %v", err)
}
if actual.ObjectMeta.Labels["a"] != "b" {
t.Fatalf("Failed to sync route")
}
if actual.Spec.Host != "test-eclipse-che.domain" {
t.Fatalf("Failed to sync route")
}
}

View File

@ -13,10 +13,8 @@ package deploy
import (
"context"
"fmt"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
@ -34,69 +32,14 @@ var secretDiffOpts = cmp.Options{
}
// SyncSecret applies secret into cluster or external namespace
func SyncSecret(
func SyncSecretToCluster(
deployContext *DeployContext,
name string,
namespace string,
data map[string][]byte) (*corev1.Secret, error) {
data map[string][]byte) (bool, error) {
specSecret, err := GetSpecSecret(deployContext, name, namespace, data)
if err != nil {
return nil, err
}
clusterSecret, err := GetSecret(deployContext, specSecret.Name, specSecret.Namespace)
if err != nil {
return nil, err
}
if clusterSecret == nil {
logrus.Infof("Creating a new object: %s, name %s", specSecret.Kind, specSecret.Name)
err := deployContext.ClusterAPI.Client.Create(context.TODO(), specSecret)
return specSecret, err
}
diff := cmp.Diff(clusterSecret, specSecret, secretDiffOpts)
if len(diff) > 0 {
logrus.Infof("Updating existed object: %s, name: %s", clusterSecret.Kind, clusterSecret.Name)
fmt.Printf("Difference:\n%s", diff)
err := deployContext.ClusterAPI.Client.Delete(context.TODO(), clusterSecret)
if err != nil {
return nil, err
}
err = deployContext.ClusterAPI.Client.Create(context.TODO(), specSecret)
if err != nil {
return nil, err
}
}
return clusterSecret, nil
}
// GetSecret retrieves given secret from cluster
func GetSecret(deployContext *DeployContext, name string, namespace string) (*corev1.Secret, error) {
secret := &corev1.Secret{}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var err error
if namespace == deployContext.CheCluster.ObjectMeta.Namespace {
err = deployContext.ClusterAPI.Client.Get(context.TODO(), namespacedName, secret)
} else {
err = deployContext.ClusterAPI.NonCachedClient.Get(context.TODO(), namespacedName, secret)
}
if err != nil {
if errors.IsNotFound(err) {
return nil, nil
}
return nil, err
}
return secret, nil
secretSpec := GetSecretSpec(deployContext, name, namespace, data)
return Sync(deployContext, secretSpec, secretDiffOpts)
}
// Get all secrets by labels and annotations
@ -139,8 +82,8 @@ func GetSecrets(deployContext *DeployContext, labels map[string]string, annotati
return secrets, nil
}
// GetSpecSecret return default secret config for given data
func GetSpecSecret(deployContext *DeployContext, name string, namespace string, data map[string][]byte) (*corev1.Secret, error) {
// GetSecretSpec return default secret config for given data
func GetSecretSpec(deployContext *DeployContext, name string, namespace string, data map[string][]byte) *corev1.Secret {
labels := GetLabels(deployContext.CheCluster, DefaultCheFlavor(deployContext.CheCluster))
secret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
@ -155,14 +98,7 @@ func GetSpecSecret(deployContext *DeployContext, name string, namespace string,
Data: data,
}
if deployContext.CheCluster.Namespace == namespace {
err := controllerutil.SetControllerReference(deployContext.CheCluster, secret, deployContext.ClusterAPI.Scheme)
if err != nil {
return nil, err
}
}
return secret, nil
return secret
}
// CreateTLSSecretFromEndpoint creates TLS secret with given name which contains certificates obtained from the given url.
@ -177,7 +113,7 @@ func CreateTLSSecretFromEndpoint(deployContext *DeployContext, url string, name
return err
}
secret, err = SyncSecret(deployContext, name, deployContext.CheCluster.Namespace, map[string][]byte{"ca.crt": crtBytes})
_, err = SyncSecretToCluster(deployContext, name, deployContext.CheCluster.Namespace, map[string][]byte{"ca.crt": crtBytes})
if err != nil {
return err
}
@ -185,24 +121,3 @@ func CreateTLSSecretFromEndpoint(deployContext *DeployContext, url string, name
return nil
}
// DeleteSecret - delete secret by name and namespace
func DeleteSecret(secretName string, namespace string, runtimeClient client.Client) error {
logrus.Infof("Delete secret: %s in the namespace: %s", secretName, namespace)
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
},
}
if err := runtimeClient.Delete(context.TODO(), secret); err != nil {
if errors.IsNotFound(err) {
return nil
}
return err
}
return nil
}

View File

@ -12,12 +12,14 @@
package deploy
import (
"context"
"os"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
@ -163,3 +165,45 @@ func TestGetSecrets(t *testing.T) {
})
}
}
func TestSyncSecretToCluster(t *testing.T) {
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
done, err := SyncSecretToCluster(deployContext, "test", "eclipse-che", map[string][]byte{"A": []byte("AAAA")})
if !done || err != nil {
t.Fatalf("Failed to sync secret: %v", err)
}
// sync another secret
done, err = SyncSecretToCluster(deployContext, "test", "eclipse-che", map[string][]byte{"B": []byte("BBBB")})
if !done || err != nil {
t.Fatalf("Failed to sync secret: %v", err)
}
actual := &corev1.Secret{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "test"}, actual)
if err != nil {
t.Fatalf("Failed to get secret: %v", err)
}
if len(actual.Data) != 1 {
t.Fatalf("Failed to sync secret: %v", err)
}
if string(actual.Data["B"]) != "BBBB" {
t.Fatalf("Failed to sync secret: %v", err)
}
}

View File

@ -294,11 +294,12 @@ func GetCheConfigMapData(deployContext *deploy.DeployContext) (cheEnv map[string
// than Che server namespace, from where the Che TLS secret is not accessable
if !util.IsWorkspaceInSameNamespaceWithChe(deployContext.CheCluster) {
if deployContext.CheCluster.Spec.K8s.TlsSecretName != "" {
cheTLSSecret, err := deploy.GetSecret(deployContext, deployContext.CheCluster.Spec.K8s.TlsSecretName, deployContext.CheCluster.ObjectMeta.Namespace)
cheTLSSecret := &corev1.Secret{}
exists, err := deploy.GetNamespacedObject(deployContext, deployContext.CheCluster.Spec.K8s.TlsSecretName, cheTLSSecret)
if err != nil {
return nil, err
}
if cheTLSSecret == nil {
if !exists {
return nil, fmt.Errorf("%s secret not found", deployContext.CheCluster.Spec.K8s.TlsSecretName)
} else {
if _, exists := cheTLSSecret.Data["tls.key"]; !exists {

View File

@ -13,9 +13,10 @@ package server
import (
"fmt"
"github.com/eclipse-che/che-operator/pkg/deploy"
"testing"
"github.com/eclipse-che/che-operator/pkg/deploy"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
corev1 "k8s.io/api/core/v1"
)
@ -44,11 +45,7 @@ func TestCreateCheDefaultService(t *testing.T) {
CheCluster: cheCluster,
ClusterAPI: deploy.ClusterAPI{},
}
service, err := GetSpecCheService(deployContext)
if service == nil || err != nil {
t.Error("service should be created witn no error")
}
service := GetSpecCheService(deployContext)
ports := service.Spec.Ports
if len(ports) != 1 {
t.Error("expected 1 default port")
@ -69,11 +66,7 @@ func TestCreateCheServerDebug(t *testing.T) {
ClusterAPI: deploy.ClusterAPI{},
}
service, err := GetSpecCheService(deployContext)
if service == nil || err != nil {
t.Error("service should be created without error")
}
service := GetSpecCheService(deployContext)
ports := service.Spec.Ports
if len(ports) != 2 {
t.Error("expected 2 default port")
@ -96,11 +89,7 @@ func TestCreateCheServiceEnableMetrics(t *testing.T) {
ClusterAPI: deploy.ClusterAPI{},
}
service, err := GetSpecCheService(deployContext)
if service == nil || err != nil {
t.Error("service should be created witn no error")
}
service := GetSpecCheService(deployContext)
ports := service.Spec.Ports
if len(ports) != 1 {
t.Error("expected 1 default port")
@ -122,11 +111,7 @@ func TestCreateCheServiceDisableMetrics(t *testing.T) {
ClusterAPI: deploy.ClusterAPI{},
}
service, err := GetSpecCheService(deployContext)
if service == nil || err != nil {
t.Error("service should be created witn no error")
}
service := GetSpecCheService(deployContext)
ports := service.Spec.Ports
if len(ports) != 2 {
t.Error("expected 2 ports")

View File

@ -16,7 +16,7 @@ import (
v1 "k8s.io/api/core/v1"
)
func GetSpecCheService(deployContext *deploy.DeployContext) (*v1.Service, error) {
func GetSpecCheService(deployContext *deploy.DeployContext) *v1.Service {
portName := []string{"http"}
portNumber := []int32{8080}
@ -30,16 +30,10 @@ func GetSpecCheService(deployContext *deploy.DeployContext) (*v1.Service, error)
portNumber = append(portNumber, deploy.DefaultCheDebugPort)
}
return deploy.GetSpecService(deployContext, deploy.CheServiceName, portName, portNumber, deploy.DefaultCheFlavor(deployContext.CheCluster))
return deploy.GetServiceSpec(deployContext, deploy.CheServiceName, portName, portNumber, deploy.DefaultCheFlavor(deployContext.CheCluster))
}
func SyncCheServiceToCluster(deployContext *deploy.DeployContext) deploy.ServiceProvisioningStatus {
specService, err := GetSpecCheService(deployContext)
if err != nil {
return deploy.ServiceProvisioningStatus{
ProvisioningStatus: deploy.ProvisioningStatus{Err: err},
}
}
return deploy.DoSyncServiceToCluster(deployContext, specService)
func SyncCheServiceToCluster(deployContext *deploy.DeployContext) (bool, error) {
specService := GetSpecCheService(deployContext)
return deploy.SyncServiceSpecToCluster(deployContext, specService)
}

View File

@ -13,31 +13,24 @@
package deploy
import (
"context"
"fmt"
"reflect"
"github.com/eclipse-che/che-operator/pkg/util"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
type ServiceProvisioningStatus struct {
ProvisioningStatus
}
const (
CheServiceName = "che-host"
)
var portsDiffOpts = cmp.Options{
cmpopts.IgnoreFields(corev1.ServicePort{}, "TargetPort", "NodePort"),
var serviceDiffOpts = cmp.Options{
cmpopts.IgnoreFields(corev1.Service{}, "TypeMeta", "ObjectMeta"),
cmp.Comparer(func(x, y corev1.ServiceSpec) bool {
return cmp.Equal(x.Ports, y.Ports, cmpopts.IgnoreFields(corev1.ServicePort{}, "TargetPort", "NodePort")) &&
reflect.DeepEqual(x.Selector, y.Selector)
}),
}
func SyncServiceToCluster(
@ -45,65 +38,22 @@ func SyncServiceToCluster(
name string,
portName []string,
portNumber []int32,
component string) ServiceProvisioningStatus {
specService, err := GetSpecService(deployContext, name, portName, portNumber, component)
if err != nil {
return ServiceProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Err: err},
}
}
component string) (bool, error) {
return DoSyncServiceToCluster(deployContext, specService)
serviceSpec := GetServiceSpec(deployContext, name, portName, portNumber, component)
return SyncServiceSpecToCluster(deployContext, serviceSpec)
}
func DoSyncServiceToCluster(deployContext *DeployContext, specService *corev1.Service) ServiceProvisioningStatus {
clusterService, err := getClusterService(specService.Name, specService.Namespace, deployContext.ClusterAPI.Client)
if err != nil {
return ServiceProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Err: err},
}
}
if clusterService == nil {
logrus.Infof("Creating a new object: %s, name %s", specService.Kind, specService.Name)
err := deployContext.ClusterAPI.Client.Create(context.TODO(), specService)
return ServiceProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
}
}
diffPorts := cmp.Diff(clusterService.Spec.Ports, specService.Spec.Ports, portsDiffOpts)
diffSelectors := cmp.Diff(clusterService.Spec.Selector, specService.Spec.Selector)
if len(diffPorts) > 0 || len(diffSelectors) > 0 {
logrus.Infof("Updating existed object: %s, name: %s", specService.Kind, specService.Name)
fmt.Printf("Ports difference:\n%s", diffPorts)
fmt.Printf("Selectors difference:\n%s", diffSelectors)
err := deployContext.ClusterAPI.Client.Delete(context.TODO(), clusterService)
if err != nil {
return ServiceProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
}
}
err = deployContext.ClusterAPI.Client.Create(context.TODO(), specService)
return ServiceProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Requeue: true, Err: err},
}
}
return ServiceProvisioningStatus{
ProvisioningStatus: ProvisioningStatus{Continue: true},
}
func SyncServiceSpecToCluster(deployContext *DeployContext, serviceSpec *corev1.Service) (bool, error) {
return Sync(deployContext, serviceSpec, serviceDiffOpts)
}
func GetSpecService(
func GetServiceSpec(
deployContext *DeployContext,
name string,
portName []string,
portNumber []int32,
component string) (*corev1.Service, error) {
component string) *corev1.Service {
labels := GetLabels(deployContext.CheCluster, component)
ports := []corev1.ServicePort{}
@ -132,28 +82,5 @@ func GetSpecService(
},
}
if !util.IsTestMode() {
err := controllerutil.SetControllerReference(deployContext.CheCluster, service, deployContext.ClusterAPI.Scheme)
if err != nil {
return nil, err
}
}
return service, nil
}
func getClusterService(name string, namespace string, client runtimeClient.Client) (*corev1.Service, error) {
service := &corev1.Service{}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := client.Get(context.TODO(), namespacedName, service)
if err != nil {
if errors.IsNotFound(err) {
return nil, nil
}
return nil, err
}
return service, nil
return service
}

View File

@ -12,54 +12,16 @@
package deploy
import (
"context"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
func SyncServiceAccountToCluster(deployContext *DeployContext, name string) (*corev1.ServiceAccount, error) {
specSA, err := getSpecServiceAccount(deployContext, name)
if err != nil {
return nil, err
}
clusterSA, err := getClusterServiceAccount(specSA.Name, specSA.Namespace, deployContext.ClusterAPI.Client)
if err != nil {
return nil, err
}
if clusterSA == nil {
logrus.Infof("Creating a new object: %s, name %s", specSA.Kind, specSA.Name)
err := deployContext.ClusterAPI.Client.Create(context.TODO(), specSA)
return nil, err
}
return clusterSA, nil
func SyncServiceAccountToCluster(deployContext *DeployContext, name string) (bool, error) {
saSpec := getServiceAccountSpec(deployContext, name)
return CreateIfNotExists(deployContext, saSpec)
}
func getClusterServiceAccount(name string, namespace string, client runtimeClient.Client) (*corev1.ServiceAccount, error) {
serviceAccount := &corev1.ServiceAccount{}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := client.Get(context.TODO(), namespacedName, serviceAccount)
if err != nil {
if errors.IsNotFound(err) {
return nil, nil
}
return nil, err
}
return serviceAccount, nil
}
func getSpecServiceAccount(deployContext *DeployContext, name string) (*corev1.ServiceAccount, error) {
func getServiceAccountSpec(deployContext *DeployContext, name string) *corev1.ServiceAccount {
labels := GetLabels(deployContext.CheCluster, DefaultCheFlavor(deployContext.CheCluster))
serviceAccount := &corev1.ServiceAccount{
TypeMeta: metav1.TypeMeta{
@ -73,10 +35,5 @@ func getSpecServiceAccount(deployContext *DeployContext, name string) (*corev1.S
},
}
err := controllerutil.SetControllerReference(deployContext.CheCluster, serviceAccount, deployContext.ClusterAPI.Scheme)
if err != nil {
return nil, err
}
return serviceAccount, nil
return serviceAccount
}

View File

@ -0,0 +1,64 @@
//
// Copyright (c) 2021 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
//
package deploy
import (
"context"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"testing"
)
func TestServiceToCluster(t *testing.T) {
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
done, err := SyncServiceToCluster(deployContext, "test", []string{"port"}, []int32{8080}, "test")
if !done || err != nil {
t.Fatalf("Failed to sync service: %v", err)
}
// sync another service
done, err = SyncServiceToCluster(deployContext, "test", []string{"port"}, []int32{9090}, "test")
if !done || err != nil {
t.Fatalf("Failed to sync service: %v", err)
}
actual := &corev1.Service{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "test"}, actual)
if err != nil {
t.Fatalf("Failed to get service: %v", err)
}
if actual.Spec.Ports[0].Port != 9090 {
t.Fatalf("Failed to sync service.")
}
}

View File

@ -315,7 +315,7 @@ func doGet(client client.Client, key client.ObjectKey, object runtime.Object) (b
}
func isUpdateUsingDeleteCreate(kind string) bool {
return "Service" == kind || "Ingress" == kind || "Route" == kind || "Job" == kind
return "Service" == kind || "Ingress" == kind || "Route" == kind || "Job" == kind || "Secret" == kind
}
func setOwnerReferenceIfNeeded(deployContext *DeployContext, blueprint metav1.Object) error {

View File

@ -135,7 +135,7 @@ func GetEndpointTLSCrtChain(deployContext *DeployContext, endpointURL string) ([
if util.IsOpenShift {
// Create test route to get certificates chain.
// Note, it is not possible to use SyncRouteToCluster here as it may cause infinite reconcile loop.
routeSpec, err := GetSpecRoute(
routeSpec, err := GetRouteSpec(
deployContext,
"test",
"",
@ -164,14 +164,15 @@ func GetEndpointTLSCrtChain(deployContext *DeployContext, endpointURL string) ([
}()
// Wait till the route is ready
var route *routev1.Route
for wait := true; wait; {
route := &routev1.Route{}
for {
time.Sleep(time.Duration(1) * time.Second)
route, err = GetClusterRoute(routeSpec.Name, routeSpec.Namespace, deployContext.ClusterAPI.Client)
exists, err := GetNamespacedObject(deployContext, routeSpec.Name, route)
if err != nil {
return nil, err
} else if exists {
break
}
wait = len(route.Spec.Host) == 0
}
requestURL = "https://" + route.Spec.Host
@ -204,16 +205,15 @@ func GetEndpointTLSCrtChain(deployContext *DeployContext, endpointURL string) ([
}()
// Wait till the ingress is ready
var ingress *v1beta1.Ingress
for wait := true; wait; {
ingress := &v1beta1.Ingress{}
for {
time.Sleep(time.Duration(1) * time.Second)
ingress := &v1beta1.Ingress{}
exists, err := GetNamespacedObject(deployContext, ingressSpec.Name, ingress)
if !exists {
if err != nil {
return nil, err
} else if exists {
break
}
wait = len(ingress.Spec.Rules[0].Host) == 0
}
requestURL = "https://" + ingress.Spec.Rules[0].Host
@ -322,12 +322,12 @@ func K8sHandleCheTLSSecrets(deployContext *DeployContext) (reconcile.Result, err
}
// Prepare permissions for the certificate generation job
sa, err := SyncServiceAccountToCluster(deployContext, CheTLSJobServiceAccountName)
if sa == nil {
done, err := SyncServiceAccountToCluster(deployContext, CheTLSJobServiceAccountName)
if !done {
return reconcile.Result{RequeueAfter: time.Second}, err
}
done, err := SyncTLSRoleToCluster(deployContext)
done, err = SyncTLSRoleToCluster(deployContext)
if !done {
return reconcile.Result{}, err
}