diff --git a/.github/workflows/minishift-e2e.yaml b/.github/workflows/minishift-e2e.yaml deleted file mode 100644 index be4722582..000000000 --- a/.github/workflows/minishift-e2e.yaml +++ /dev/null @@ -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 diff --git a/deploy.sh b/deploy.sh index 4b039e76f..888952e9e 100755 --- a/deploy.sh +++ b/deploy.sh @@ -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 diff --git a/deploy/role_binding_oauth.yaml b/deploy/role_binding_oauth.yaml deleted file mode 100644 index 2593e203e..000000000 --- a/deploy/role_binding_oauth.yaml +++ /dev/null @@ -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 diff --git a/e2e/config.go b/e2e/config.go deleted file mode 100644 index e7a189421..000000000 --- a/e2e/config.go +++ /dev/null @@ -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 -} diff --git a/e2e/create.go b/e2e/create.go deleted file mode 100644 index 01c0d355e..000000000 --- a/e2e/create.go +++ /dev/null @@ -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 -} diff --git a/e2e/delete.go b/e2e/delete.go deleted file mode 100644 index 97bdf8e9a..000000000 --- a/e2e/delete.go +++ /dev/null @@ -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 -} diff --git a/e2e/deserialize.go b/e2e/deserialize.go deleted file mode 100644 index e5590976f..000000000 --- a/e2e/deserialize.go +++ /dev/null @@ -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 -} diff --git a/e2e/get.go b/e2e/get.go deleted file mode 100644 index 9d5920614..000000000 --- a/e2e/get.go +++ /dev/null @@ -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 - -} diff --git a/e2e/patch.go b/e2e/patch.go deleted file mode 100644 index d45061bd9..000000000 --- a/e2e/patch.go +++ /dev/null @@ -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 -} diff --git a/e2e/run_tests.sh b/e2e/run_tests.sh deleted file mode 100755 index 285ddb1c7..000000000 --- a/e2e/run_tests.sh +++ /dev/null @@ -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... diff --git a/e2e/tests.go b/e2e/tests.go deleted file mode 100644 index 67ae12a7c..000000000 --- a/e2e/tests.go +++ /dev/null @@ -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) - } -} diff --git a/e2e/watch.go b/e2e/watch.go deleted file mode 100644 index 911d1420e..000000000 --- a/e2e/watch.go +++ /dev/null @@ -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 - } - } - } -} diff --git a/pkg/controller/che/che_controller.go b/pkg/controller/che/che_controller.go index 39db9dcdb..af95ac2d6 100644 --- a/pkg/controller/che/che_controller.go +++ b/pkg/controller/che/che_controller.go @@ -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 } diff --git a/pkg/controller/che/create.go b/pkg/controller/che/create.go index 720cad8ea..086f78651 100644 --- a/pkg/controller/che/create.go +++ b/pkg/controller/che/create.go @@ -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 } diff --git a/pkg/controller/che/oauth_initial_htpasswd_provider.go b/pkg/controller/che/oauth_initial_htpasswd_provider.go index ecb8c0120..65aa0fdd7 100644 --- a/pkg/controller/che/oauth_initial_htpasswd_provider.go +++ b/pkg/controller/che/oauth_initial_htpasswd_provider.go @@ -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 } diff --git a/pkg/controller/che/workspace_namespace_permission.go b/pkg/controller/che/workspace_namespace_permission.go index 9b220972e..7bf8552e4 100644 --- a/pkg/controller/che/workspace_namespace_permission.go +++ b/pkg/controller/che/workspace_namespace_permission.go @@ -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 { diff --git a/pkg/deploy/data_types.go b/pkg/deploy/data_types.go index 78989240a..7bf501c11 100644 --- a/pkg/deploy/data_types.go +++ b/pkg/deploy/data_types.go @@ -63,3 +63,7 @@ type Proxy struct { NoProxy string TrustedCAMapName string } + +type Syncable interface { + Sync() (bool, error) +} diff --git a/pkg/deploy/deployment.go b/pkg/deploy/deployment.go index fdc253b3d..edf9176be 100644 --- a/pkg/deploy/deployment.go +++ b/pkg/deploy/deployment.go @@ -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) } diff --git a/pkg/deploy/devfile-registry/devfile_registry.go b/pkg/deploy/devfile-registry/devfile_registry.go index f5706f789..d0e75d197 100644 --- a/pkg/deploy/devfile-registry/devfile_registry.go +++ b/pkg/deploy/devfile-registry/devfile_registry.go @@ -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 } } diff --git a/pkg/deploy/expose/expose.go b/pkg/deploy/expose/expose.go index 06c2a8d2e..ac1f31457 100644 --- a/pkg/deploy/expose/expose.go +++ b/pkg/deploy/expose/expose.go @@ -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 } } diff --git a/pkg/deploy/identity-provider/identity_provider.go b/pkg/deploy/identity-provider/identity_provider.go index 4576a09be..772a8834f 100644 --- a/pkg/deploy/identity-provider/identity_provider.go +++ b/pkg/deploy/identity-provider/identity_provider.go @@ -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 diff --git a/pkg/deploy/oauthclient.go b/pkg/deploy/oauthclient.go index 7fb3a2cae..a66e8005e 100644 --- a/pkg/deploy/oauthclient.go +++ b/pkg/deploy/oauthclient.go @@ -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" diff --git a/pkg/deploy/plugin-registry/plugin_registry.go b/pkg/deploy/plugin-registry/plugin_registry.go index 9339629a4..f34b74e77 100644 --- a/pkg/deploy/plugin-registry/plugin_registry.go +++ b/pkg/deploy/plugin-registry/plugin_registry.go @@ -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) diff --git a/pkg/deploy/postgres/deployment_postgres.go b/pkg/deploy/postgres/postgres.go similarity index 53% rename from pkg/deploy/postgres/deployment_postgres.go rename to pkg/deploy/postgres/postgres.go index cb8ea6710..af47a4dec 100644 --- a/pkg/deploy/postgres/deployment_postgres.go +++ b/pkg/deploy/postgres/postgres.go @@ -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, diff --git a/pkg/deploy/postgres/deployment_posgres_test.go b/pkg/deploy/postgres/postgres_test.go similarity index 66% rename from pkg/deploy/postgres/deployment_posgres_test.go rename to pkg/deploy/postgres/postgres_test.go index fbb914ac3..9bb982350 100644 --- a/pkg/deploy/postgres/deployment_posgres_test.go +++ b/pkg/deploy/postgres/postgres_test.go @@ -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) + } +} diff --git a/pkg/deploy/route.go b/pkg/deploy/route.go index 1533abcd5..814aed040 100644 --- a/pkg/deploy/route.go +++ b/pkg/deploy/route.go @@ -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 } diff --git a/pkg/deploy/route_test.go b/pkg/deploy/route_test.go index 3c8998764..ef426a035 100644 --- a/pkg/deploy/route_test.go +++ b/pkg/deploy/route_test.go @@ -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") + } +} diff --git a/pkg/deploy/secret.go b/pkg/deploy/secret.go index 9bece38f5..56d923d53 100644 --- a/pkg/deploy/secret.go +++ b/pkg/deploy/secret.go @@ -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 -} diff --git a/pkg/deploy/sercet_test.go b/pkg/deploy/sercet_test.go index 3051913cb..8c9961e8d 100644 --- a/pkg/deploy/sercet_test.go +++ b/pkg/deploy/sercet_test.go @@ -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) + } +} diff --git a/pkg/deploy/server/che_configmap.go b/pkg/deploy/server/che_configmap.go index 0ceb06522..32207fc2e 100644 --- a/pkg/deploy/server/che_configmap.go +++ b/pkg/deploy/server/che_configmap.go @@ -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 { diff --git a/pkg/deploy/server/che_service_test.go b/pkg/deploy/server/che_service_test.go index 2ae35c433..9d8be2d42 100644 --- a/pkg/deploy/server/che_service_test.go +++ b/pkg/deploy/server/che_service_test.go @@ -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") diff --git a/pkg/deploy/server/service.go b/pkg/deploy/server/service.go index b1010da59..eac039001 100644 --- a/pkg/deploy/server/service.go +++ b/pkg/deploy/server/service.go @@ -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) } diff --git a/pkg/deploy/service.go b/pkg/deploy/service.go index 1c88139c4..d1c2ee02d 100644 --- a/pkg/deploy/service.go +++ b/pkg/deploy/service.go @@ -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 } diff --git a/pkg/deploy/service_account.go b/pkg/deploy/service_account.go index 4a7b09da2..0cd31ca17 100644 --- a/pkg/deploy/service_account.go +++ b/pkg/deploy/service_account.go @@ -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 } diff --git a/pkg/deploy/service_test.go b/pkg/deploy/service_test.go new file mode 100644 index 000000000..9401f1340 --- /dev/null +++ b/pkg/deploy/service_test.go @@ -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.") + } +} diff --git a/pkg/deploy/sync.go b/pkg/deploy/sync.go index 89034cdc2..941bca7d7 100644 --- a/pkg/deploy/sync.go +++ b/pkg/deploy/sync.go @@ -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 { diff --git a/pkg/deploy/tls.go b/pkg/deploy/tls.go index 6405cbf96..ac993c651 100644 --- a/pkg/deploy/tls.go +++ b/pkg/deploy/tls.go @@ -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 }