Allow to configure github and bitbucket oauth config (#677)
* Allow to configure github and bitbucket oauth config Signed-off-by: Anatolii Bazko <abazko@redhat.com>pull/679/head
parent
5f2b348932
commit
75da259f72
|
|
@ -27,7 +27,7 @@ RUN export ARCH="$(uname -m)" && if [[ ${ARCH} == "x86_64" ]]; then export ARCH=
|
|||
GOOS=linux GOARCH=${ARCH} CGO_ENABLED=0 go build -mod=vendor -o /tmp/che-operator/che-operator cmd/manager/main.go
|
||||
|
||||
# https://access.redhat.com/containers/?tab=tags#/registry.access.redhat.com/ubi8-minimal
|
||||
FROM registry.access.redhat.com/ubi8-minimal:8.3-230
|
||||
FROM registry.access.redhat.com/ubi8-minimal:8.3-291
|
||||
|
||||
COPY --from=builder /tmp/che-operator/che-operator /usr/local/bin/che-operator
|
||||
COPY --from=builder /che-operator/templates/keycloak-provision.sh /tmp/keycloak-provision.sh
|
||||
|
|
|
|||
|
|
@ -85,13 +85,13 @@ metadata:
|
|||
categories: Developer Tools
|
||||
certified: "false"
|
||||
containerImage: quay.io/eclipse/che-operator:nightly
|
||||
createdAt: "2021-02-15T16:16:52Z"
|
||||
createdAt: "2021-02-17T11:12:17Z"
|
||||
description: A Kube-native development solution that delivers portable and collaborative
|
||||
developer workspaces.
|
||||
operatorframework.io/suggested-namespace: eclipse-che
|
||||
repository: https://github.com/eclipse/che-operator
|
||||
support: Eclipse Foundation
|
||||
name: eclipse-che-preview-kubernetes.v7.27.0-102.nightly
|
||||
name: eclipse-che-preview-kubernetes.v7.27.0-104.nightly
|
||||
namespace: placeholder
|
||||
spec:
|
||||
apiservicedefinitions: {}
|
||||
|
|
@ -482,7 +482,7 @@ spec:
|
|||
- name: RELATED_IMAGE_che_tls_secrets_creation_job
|
||||
value: quay.io/eclipse/che-tls-secret-creator:alpine-d1ed4ad
|
||||
- name: RELATED_IMAGE_pvc_jobs
|
||||
value: registry.access.redhat.com/ubi8-minimal:8.3-230
|
||||
value: registry.access.redhat.com/ubi8-minimal:8.3-291
|
||||
- name: RELATED_IMAGE_postgres
|
||||
value: quay.io/eclipse/che--centos--postgresql-96-centos7:9.6-b681d78125361519180a6ac05242c296f8906c11eab7e207b5ca9a89b6344392
|
||||
- name: RELATED_IMAGE_keycloak
|
||||
|
|
@ -685,4 +685,4 @@ spec:
|
|||
maturity: stable
|
||||
provider:
|
||||
name: Eclipse Foundation
|
||||
version: 7.27.0-102.nightly
|
||||
version: 7.27.0-104.nightly
|
||||
|
|
|
|||
|
|
@ -76,13 +76,13 @@ metadata:
|
|||
categories: Developer Tools, OpenShift Optional
|
||||
certified: "false"
|
||||
containerImage: quay.io/eclipse/che-operator:nightly
|
||||
createdAt: "2021-02-15T16:16:59Z"
|
||||
createdAt: "2021-02-17T11:12:27Z"
|
||||
description: A Kube-native development solution that delivers portable and collaborative
|
||||
developer workspaces in OpenShift.
|
||||
operatorframework.io/suggested-namespace: eclipse-che
|
||||
repository: https://github.com/eclipse/che-operator
|
||||
support: Eclipse Foundation
|
||||
name: eclipse-che-preview-openshift.v7.27.0-102.nightly
|
||||
name: eclipse-che-preview-openshift.v7.27.0-104.nightly
|
||||
namespace: placeholder
|
||||
spec:
|
||||
apiservicedefinitions: {}
|
||||
|
|
@ -548,7 +548,7 @@ spec:
|
|||
- name: RELATED_IMAGE_devfile_registry
|
||||
value: quay.io/eclipse/che-devfile-registry:nightly
|
||||
- name: RELATED_IMAGE_pvc_jobs
|
||||
value: registry.access.redhat.com/ubi8-minimal:8.3-230
|
||||
value: registry.access.redhat.com/ubi8-minimal:8.3-291
|
||||
- name: RELATED_IMAGE_postgres
|
||||
value: quay.io/eclipse/che--centos--postgresql-96-centos7:9.6-b681d78125361519180a6ac05242c296f8906c11eab7e207b5ca9a89b6344392
|
||||
- name: RELATED_IMAGE_keycloak
|
||||
|
|
@ -757,4 +757,4 @@ spec:
|
|||
maturity: stable
|
||||
provider:
|
||||
name: Eclipse Foundation
|
||||
version: 7.27.0-102.nightly
|
||||
version: 7.27.0-104.nightly
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ spec:
|
|||
- name: RELATED_IMAGE_che_tls_secrets_creation_job
|
||||
value: quay.io/eclipse/che-tls-secret-creator:alpine-d1ed4ad
|
||||
- name: RELATED_IMAGE_pvc_jobs
|
||||
value: registry.access.redhat.com/ubi8-minimal:8.3-230
|
||||
value: registry.access.redhat.com/ubi8-minimal:8.3-291
|
||||
- name: RELATED_IMAGE_postgres
|
||||
value: quay.io/eclipse/che--centos--postgresql-96-centos7:9.6-b681d78125361519180a6ac05242c296f8906c11eab7e207b5ca9a89b6344392
|
||||
- name: RELATED_IMAGE_keycloak
|
||||
|
|
|
|||
1
go.sum
1
go.sum
|
|
@ -1014,6 +1014,7 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
|
|||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo=
|
||||
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
|
|
|
|||
|
|
@ -101,7 +101,8 @@ const (
|
|||
KubernetesInstanceLabelKey = "app.kubernetes.io/instance"
|
||||
KubernetesNameLabelKey = "app.kubernetes.io/name"
|
||||
|
||||
CheEclipseOrg = "che.eclipse.org"
|
||||
CheEclipseOrg = "che.eclipse.org"
|
||||
OAuthScmConfiguration = "oauth-scm-configuration"
|
||||
|
||||
// che.eclipse.org annotations
|
||||
CheEclipseOrgMountPath = "che.eclipse.org/mount-path"
|
||||
|
|
@ -109,6 +110,8 @@ const (
|
|||
CheEclipseOrgEnvName = "che.eclipse.org/env-name"
|
||||
CheEclipseOrgNamespace = "che.eclipse.org/namespace"
|
||||
CheEclipseOrgGithubOAuthCredentials = "che.eclipse.org/github-oauth-credentials"
|
||||
CheEclipseOrgOAuthScmServer = "che.eclipse.org/oauth-scm-server"
|
||||
CheEclipseOrgScmServerEndpoint = "che.eclipse.org/scm-server-endpoint"
|
||||
|
||||
// components
|
||||
IdentityProviderName = "keycloak"
|
||||
|
|
@ -141,6 +144,10 @@ const (
|
|||
DefaultPostgresMemoryRequest = "512Mi"
|
||||
DefaultPostgresCpuLimit = "500m"
|
||||
DefaultPostgresCpuRequest = "100m"
|
||||
|
||||
BitBucketOAuthConfigMountPath = "/che-conf/oauth/bitbucket"
|
||||
BitBucketOAuthConfigPrivateKey = "private.key"
|
||||
BitBucketOAuthConfigConsumerKey = "consumer.key"
|
||||
)
|
||||
|
||||
func InitDefaults(defaultsPath string) {
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ func MountSecrets(specDeployment *appsv1.Deployment, deployContext *DeployContex
|
|||
return strings.Compare(secrets.Items[i].Name, secrets.Items[j].Name) < 0
|
||||
})
|
||||
|
||||
container := &specDeployment.Spec.Template.Spec.Containers[0]
|
||||
for _, secretObj := range secrets.Items {
|
||||
switch secretObj.Annotations[CheEclipseOrgMountAs] {
|
||||
case "file":
|
||||
|
|
@ -157,7 +158,7 @@ func MountSecrets(specDeployment *appsv1.Deployment, deployContext *DeployContex
|
|||
}
|
||||
|
||||
specDeployment.Spec.Template.Spec.Volumes = append(specDeployment.Spec.Template.Spec.Volumes, volume)
|
||||
specDeployment.Spec.Template.Spec.Containers[0].VolumeMounts = append(specDeployment.Spec.Template.Spec.Containers[0].VolumeMounts, volumeMount)
|
||||
container.VolumeMounts = append(container.VolumeMounts, volumeMount)
|
||||
|
||||
case "env":
|
||||
secret, err := GetSecret(deployContext, secretObj.Name, deployContext.CheCluster.Namespace)
|
||||
|
|
@ -203,7 +204,7 @@ func MountSecrets(specDeployment *appsv1.Deployment, deployContext *DeployContex
|
|||
},
|
||||
},
|
||||
}
|
||||
specDeployment.Spec.Template.Spec.Containers[0].Env = append(specDeployment.Spec.Template.Spec.Containers[0].Env, env)
|
||||
container.Env = append(container.Env, env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,12 +89,15 @@ func GetSpecKeycloakDeployment(
|
|||
}
|
||||
|
||||
if clusterDeployment != nil {
|
||||
env := clusterDeployment.Spec.Template.Spec.Containers[0].Env
|
||||
for _, e := range env {
|
||||
// To be compatible with prev deployments when "TRUSTPASS" env was used
|
||||
if "TRUSTPASS" == e.Name || "SSO_TRUSTSTORE_PASSWORD" == e.Name {
|
||||
trustpass = e.Value
|
||||
break
|
||||
// To be compatible with prev deployments when "TRUSTPASS" env was used
|
||||
clusterContainer := &clusterDeployment.Spec.Template.Spec.Containers[0]
|
||||
env := util.FindEnv(clusterContainer.Env, "TRUSTPASS")
|
||||
if env != nil {
|
||||
trustpass = env.Value
|
||||
} else {
|
||||
env := util.FindEnv(clusterContainer.Env, "SSO_TRUSTSTORE_PASSWORD")
|
||||
if env != nil {
|
||||
trustpass = env.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -477,6 +480,40 @@ func GetSpecKeycloakDeployment(
|
|||
}
|
||||
}
|
||||
|
||||
// Mount GITHUB_CLIENT_ID and GITHUB_SECRET to keycloak container
|
||||
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
|
||||
}, map[string]string{
|
||||
deploy.CheEclipseOrgOAuthScmServer: "github",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(secrets) == 1 {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "GITHUB_CLIENT_ID",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "id",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: secrets[0].Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, corev1.EnvVar{
|
||||
Name: "GITHUB_SECRET",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "secret",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: secrets[0].Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for _, envvar := range proxyEnvVars {
|
||||
keycloakEnv = append(keycloakEnv, envvar)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,15 @@ package identity_provider
|
|||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/eclipse/che-operator/pkg/util"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/eclipse/che-operator/pkg/deploy"
|
||||
|
||||
orgv1 "github.com/eclipse/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/client-go/kubernetes/scheme"
|
||||
|
|
@ -117,3 +120,103 @@ func TestDeployment(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountGitHubOAuthEnvVar(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
initObjects []runtime.Object
|
||||
cheCluster *orgv1.CheCluster
|
||||
expectedIdEnv corev1.EnvVar
|
||||
expectedSecretEnv corev1.EnvVar
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Test",
|
||||
initObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "github-oauth-config",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "che.eclipse.org",
|
||||
"app.kubernetes.io/component": "oauth-scm-configuration",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"che.eclipse.org/oauth-scm-server": "github",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"id": []byte("some__id"),
|
||||
"secret": []byte("some_secret"),
|
||||
},
|
||||
},
|
||||
},
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
},
|
||||
expectedIdEnv: corev1.EnvVar{
|
||||
Name: "GITHUB_CLIENT_ID",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "id",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "github-oauth-config",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedSecretEnv: corev1.EnvVar{
|
||||
Name: "GITHUB_SECRET",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "secret",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "github-oauth-config",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.LoggerTo(os.Stdout, true))
|
||||
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
testCase.initObjects = append(testCase.initObjects)
|
||||
cli := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: testCase.cheCluster,
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
Proxy: &deploy.Proxy{},
|
||||
}
|
||||
|
||||
deployment, err := GetSpecKeycloakDeployment(deployContext, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating deployment: %v", err)
|
||||
}
|
||||
|
||||
container := &deployment.Spec.Template.Spec.Containers[0]
|
||||
idEnv := util.FindEnv(container.Env, "GITHUB_CLIENT_ID")
|
||||
if !reflect.DeepEqual(testCase.expectedIdEnv, *idEnv) {
|
||||
t.Errorf("Expected Env and Env returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedIdEnv, idEnv))
|
||||
}
|
||||
|
||||
secretEnv := util.FindEnv(container.Env, "GITHUB_SECRET")
|
||||
if !reflect.DeepEqual(testCase.expectedSecretEnv, *secretEnv) {
|
||||
t.Errorf("Expected CR and CR returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedSecretEnv, secretEnv))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,22 +13,18 @@ package identity_provider
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
|
||||
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
|
||||
"github.com/eclipse/che-operator/pkg/deploy"
|
||||
"github.com/eclipse/che-operator/pkg/deploy/expose"
|
||||
"github.com/eclipse/che-operator/pkg/util"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
oauth "github.com/openshift/api/oauth/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -128,7 +124,7 @@ func syncKeycloakResources(deployContext *deploy.DeployContext) (bool, error) {
|
|||
for {
|
||||
cr.Status.KeycloakProvisoned = true
|
||||
if err := deploy.UpdateCheCRStatus(deployContext, "status: provisioned with Keycloak", "true"); err != nil &&
|
||||
errors.IsConflict(err) {
|
||||
apierrors.IsConflict(err) {
|
||||
|
||||
reload(deployContext)
|
||||
continue
|
||||
|
|
@ -197,7 +193,7 @@ func SyncOpenShiftIdentityProviderItems(deployContext *deploy.DeployContext) (bo
|
|||
for {
|
||||
cr.Status.OpenShiftoAuthProvisioned = true
|
||||
if err := deploy.UpdateCheCRStatus(deployContext, "status: provisioned with OpenShift identity provider", "true"); err != nil &&
|
||||
errors.IsConflict(err) {
|
||||
apierrors.IsConflict(err) {
|
||||
|
||||
reload(deployContext)
|
||||
continue
|
||||
|
|
@ -209,34 +205,37 @@ func SyncOpenShiftIdentityProviderItems(deployContext *deploy.DeployContext) (bo
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// SyncGitHubOAuth provisions GitHub OAuth if secret with
|
||||
// annotation `che.eclipse.org/github-oauth-credentials=true` is mounted into a container
|
||||
// SyncGitHubOAuth provisions GitHub OAuth if secret with annotation
|
||||
// `che.eclipse.org/github-oauth-credentials=true` or `che.eclipse.org/oauth-scm-configuration=github`
|
||||
// is mounted into a container
|
||||
func SyncGitHubOAuth(deployContext *deploy.DeployContext) (bool, error) {
|
||||
cr := deployContext.CheCluster
|
||||
|
||||
// find mounted GitHug OAuth credentials
|
||||
secrets := &corev1.SecretList{}
|
||||
|
||||
kubernetesPartOfLabelSelectorRequirement, _ := labels.NewRequirement(deploy.KubernetesPartOfLabelKey, selection.Equals, []string{deploy.CheEclipseOrg})
|
||||
kubernetesComponentLabelSelectorRequirement, _ := labels.NewRequirement(deploy.KubernetesComponentLabelKey, selection.Equals, []string{deploy.IdentityProviderName + "-secret"})
|
||||
|
||||
listOptions := &client.ListOptions{
|
||||
LabelSelector: labels.NewSelector().
|
||||
Add(*kubernetesPartOfLabelSelectorRequirement).
|
||||
Add(*kubernetesComponentLabelSelectorRequirement),
|
||||
}
|
||||
if err := deployContext.ClusterAPI.Client.List(context.TODO(), secrets, listOptions); err != nil {
|
||||
// get legacy secret
|
||||
legacySecrets, err := deploy.GetSecrets(deployContext, map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
deploy.KubernetesComponentLabelKey: deploy.IdentityProviderName + "-secret",
|
||||
}, map[string]string{
|
||||
deploy.CheEclipseOrgGithubOAuthCredentials: "true",
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
isGitHubOAuthCredentialsExists := false
|
||||
for _, secret := range secrets.Items {
|
||||
if secret.Annotations[deploy.CheEclipseOrgGithubOAuthCredentials] == "true" {
|
||||
isGitHubOAuthCredentialsExists = true
|
||||
break
|
||||
}
|
||||
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
|
||||
}, map[string]string{
|
||||
deploy.CheEclipseOrgOAuthScmServer: "github",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if len(secrets)+len(legacySecrets) > 1 {
|
||||
return false, errors.New("More than 1 GitHub OAuth configuration secrets found")
|
||||
}
|
||||
|
||||
isGitHubOAuthCredentialsExists := len(secrets) == 1 || len(legacySecrets) == 1
|
||||
cr := deployContext.CheCluster
|
||||
|
||||
if isGitHubOAuthCredentialsExists {
|
||||
if !cr.Status.GitHubOAuthProvisioned {
|
||||
if !util.IsTestMode() {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ func TestSyncGitHubOAuth(t *testing.T) {
|
|||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Should provision GitHub OAuth",
|
||||
name: "Should provision GitHub OAuth with legacy secret",
|
||||
initCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
|
|
@ -79,6 +79,42 @@ func TestSyncGitHubOAuth(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should provision GitHub OAuth",
|
||||
initCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
},
|
||||
expectedCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
GitHubOAuthProvisioned: true,
|
||||
},
|
||||
},
|
||||
initObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "github-oauth-config",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "che.eclipse.org",
|
||||
"app.kubernetes.io/component": "oauth-scm-configuration",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"che.eclipse.org/oauth-scm-server": "github",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should not provision GitHub OAuth",
|
||||
initCR: &orgv1.CheCluster{
|
||||
|
|
|
|||
|
|
@ -52,12 +52,10 @@ func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeplo
|
|||
pullPolicy := corev1.PullPolicy(util.GetValue(string(deployContext.CheCluster.Spec.Database.PostgresImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(postgresImage)))
|
||||
|
||||
if clusterDeployment != nil {
|
||||
env := clusterDeployment.Spec.Template.Spec.Containers[0].Env
|
||||
for _, e := range env {
|
||||
if "POSTGRESQL_ADMIN_PASSWORD" == e.Name {
|
||||
postgresAdminPassword = e.Value
|
||||
break
|
||||
}
|
||||
clusterContainer := &clusterDeployment.Spec.Template.Spec.Containers[0]
|
||||
env := util.FindEnv(clusterContainer.Env, "POSTGRESQL_ADMIN_PASSWORD")
|
||||
if env != nil {
|
||||
postgresAdminPassword = env.Value
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,9 +177,11 @@ func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeplo
|
|||
},
|
||||
}
|
||||
|
||||
container := &deployment.Spec.Template.Spec.Containers[0]
|
||||
|
||||
chePostgresSecret := deployContext.CheCluster.Spec.Database.ChePostgresSecret
|
||||
if len(chePostgresSecret) > 0 {
|
||||
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env,
|
||||
container.Env = append(container.Env,
|
||||
corev1.EnvVar{
|
||||
Name: "POSTGRESQL_USER",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
|
|
@ -204,7 +204,7 @@ func GetSpecPostgresDeployment(deployContext *deploy.DeployContext, clusterDeplo
|
|||
},
|
||||
})
|
||||
} else {
|
||||
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env,
|
||||
container.Env = append(container.Env,
|
||||
corev1.EnvVar{
|
||||
Name: "POSTGRESQL_USER",
|
||||
Value: deployContext.CheCluster.Spec.Database.ChePostgresUser,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import (
|
|||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8slabels "k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
|
|
@ -97,6 +99,46 @@ func GetSecret(deployContext *DeployContext, name string, namespace string) (*co
|
|||
return secret, nil
|
||||
}
|
||||
|
||||
// Get all secrets by labels and annotations
|
||||
func GetSecrets(deployContext *DeployContext, labels map[string]string, annotations map[string]string) ([]corev1.Secret, error) {
|
||||
secrets := []corev1.Secret{}
|
||||
|
||||
labelSelector := k8slabels.NewSelector()
|
||||
for k, v := range labels {
|
||||
req, err := k8slabels.NewRequirement(k, selection.Equals, []string{v})
|
||||
if err != nil {
|
||||
return secrets, err
|
||||
}
|
||||
labelSelector = labelSelector.Add(*req)
|
||||
}
|
||||
|
||||
listOptions := &client.ListOptions{
|
||||
Namespace: deployContext.CheCluster.Namespace,
|
||||
LabelSelector: labelSelector,
|
||||
}
|
||||
secretList := &corev1.SecretList{}
|
||||
if err := deployContext.ClusterAPI.Client.List(context.TODO(), secretList, listOptions); err != nil {
|
||||
return secrets, err
|
||||
}
|
||||
|
||||
for _, secret := range secretList.Items {
|
||||
annotationsOk := true
|
||||
for k, v := range annotations {
|
||||
_, annotationExists := secret.Annotations[k]
|
||||
if !annotationExists || secret.Annotations[k] != v {
|
||||
annotationsOk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if annotationsOk {
|
||||
secrets = append(secrets, secret)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
labels := GetLabels(deployContext.CheCluster, DefaultCheFlavor(deployContext.CheCluster))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,165 @@
|
|||
//
|
||||
// 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 deploy
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
orgv1 "github.com/eclipse/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/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetSecrets(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
labels map[string]string
|
||||
annotations map[string]string
|
||||
initObjects []runtime.Object
|
||||
expectedAmount int
|
||||
}
|
||||
|
||||
runtimeSecrets := []runtime.Object{
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test2",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"l1": "v1",
|
||||
"l2": "v2",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"a1": "v1",
|
||||
"a2": "v2",
|
||||
},
|
||||
},
|
||||
},
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test1",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"l1": "v1",
|
||||
"l3": "v3",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"a1": "v1",
|
||||
"a3": "v3",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Get secrets",
|
||||
initObjects: []runtime.Object{},
|
||||
labels: map[string]string{
|
||||
"l1": "v1",
|
||||
},
|
||||
annotations: map[string]string{
|
||||
"a1": "v1",
|
||||
},
|
||||
expectedAmount: 2,
|
||||
},
|
||||
{
|
||||
name: "Get secrets",
|
||||
initObjects: []runtime.Object{},
|
||||
labels: map[string]string{
|
||||
"l1": "v1",
|
||||
},
|
||||
annotations: map[string]string{
|
||||
"a1": "v1",
|
||||
"a2": "v2",
|
||||
},
|
||||
expectedAmount: 1,
|
||||
},
|
||||
{
|
||||
name: "Get secrets",
|
||||
initObjects: []runtime.Object{},
|
||||
labels: map[string]string{
|
||||
"l1": "v1",
|
||||
"l2": "v2",
|
||||
},
|
||||
annotations: map[string]string{
|
||||
"a1": "v1",
|
||||
},
|
||||
expectedAmount: 1,
|
||||
},
|
||||
{
|
||||
name: "Get secrets, unknown label",
|
||||
initObjects: []runtime.Object{},
|
||||
labels: map[string]string{
|
||||
"l4": "v4",
|
||||
},
|
||||
annotations: map[string]string{},
|
||||
expectedAmount: 0,
|
||||
},
|
||||
{
|
||||
name: "Get secrets, unknown annotation",
|
||||
initObjects: []runtime.Object{},
|
||||
labels: map[string]string{
|
||||
"l1": "v1",
|
||||
},
|
||||
annotations: map[string]string{
|
||||
"a4": "v4",
|
||||
},
|
||||
expectedAmount: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.LoggerTo(os.Stdout, true))
|
||||
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
testCase.initObjects = append(testCase.initObjects, runtimeSecrets...)
|
||||
cli := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
|
||||
deployContext := &DeployContext{
|
||||
CheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
},
|
||||
ClusterAPI: ClusterAPI{
|
||||
Client: cli,
|
||||
NonCachedClient: cli,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
}
|
||||
|
||||
secrets, err := GetSecrets(deployContext, testCase.labels, testCase.annotations)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting secrets: %v", err)
|
||||
}
|
||||
|
||||
if len(secrets) != testCase.expectedAmount {
|
||||
t.Fatalf("Expected %d but found: %d", testCase.expectedAmount, len(secrets))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -304,6 +304,26 @@ func GetCheConfigMapData(deployContext *deploy.DeployContext) (cheEnv map[string
|
|||
}
|
||||
|
||||
addMap(cheEnv, deployContext.CheCluster.Spec.Server.CustomCheProperties)
|
||||
|
||||
// Update BitBucket endpoints
|
||||
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
|
||||
}, map[string]string{
|
||||
deploy.CheEclipseOrgOAuthScmServer: "bitbucket",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(secrets) == 1 {
|
||||
serverEndpoint := secrets[0].Annotations[deploy.CheEclipseOrgScmServerEndpoint]
|
||||
endpoints, exists := cheEnv["CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS"]
|
||||
if exists {
|
||||
cheEnv["CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS"] = endpoints + "," + serverEndpoint
|
||||
} else {
|
||||
cheEnv["CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS"] = serverEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
return cheEnv, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ package server
|
|||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/eclipse/che-operator/pkg/deploy"
|
||||
|
|
@ -30,53 +29,74 @@ import (
|
|||
)
|
||||
|
||||
func TestNewCheConfigMap(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
isOpenShift bool
|
||||
isOpenShift4 bool
|
||||
initObjects []runtime.Object
|
||||
cheCluster *orgv1.CheCluster
|
||||
expectedData map[string]string
|
||||
}
|
||||
|
||||
// since all values are retrieved from CR or auto-generated
|
||||
// some of them are explicitly set for this test to avoid using fake kube
|
||||
// and creating a CR with all spec fields pre-populated
|
||||
cr := &orgv1.CheCluster{}
|
||||
cr.Spec.Server.CheHost = "myhostname.com"
|
||||
cr.Spec.Server.TlsSupport = true
|
||||
cr.Spec.Auth.OpenShiftoAuth = util.NewBoolPointer(true)
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: cr,
|
||||
Proxy: &deploy.Proxy{},
|
||||
ClusterAPI: deploy.ClusterAPI{},
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Test",
|
||||
initObjects: []runtime.Object{},
|
||||
isOpenShift: true,
|
||||
isOpenShift4: true,
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CheHost: "myhostname.com",
|
||||
TlsSupport: true,
|
||||
CustomCheProperties: map[string]string{
|
||||
"CHE_WORKSPACE_NO_PROXY": "myproxy.myhostname.com",
|
||||
},
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER": "openshift-v4",
|
||||
"CHE_API": "https://myhostname.com/api",
|
||||
"CHE_WORKSPACE_NO_PROXY": "myproxy.myhostname.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
expectedIdentityProvider := "openshift-v4"
|
||||
util.IsOpenShift = true
|
||||
util.IsOpenShift4 = true
|
||||
|
||||
cheEnv, _ := GetCheConfigMapData(deployContext)
|
||||
testCm, _ := deploy.GetSpecConfigMap(deployContext, CheConfigMapName, cheEnv, CheConfigMapName)
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.LoggerTo(os.Stdout, true))
|
||||
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
testCase.initObjects = append(testCase.initObjects)
|
||||
cli := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
nonCachedClient := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
|
||||
identityProvider := testCm.Data["CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"]
|
||||
protocol := strings.Split(testCm.Data["CHE_API"], "://")[0]
|
||||
if identityProvider != expectedIdentityProvider {
|
||||
t.Errorf("Test failed. Expecting identity provider to be '%s' while got '%s'", expectedIdentityProvider, identityProvider)
|
||||
}
|
||||
if protocol != "https" {
|
||||
t.Errorf("Test failed. Expecting 'https' protocol, got '%s'", protocol)
|
||||
}
|
||||
}
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: testCase.cheCluster,
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
NonCachedClient: nonCachedClient,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
Proxy: &deploy.Proxy{},
|
||||
}
|
||||
|
||||
func TestConfigMapOverride(t *testing.T) {
|
||||
cr := &orgv1.CheCluster{}
|
||||
cr.Spec.Server.CheHost = "myhostname.com"
|
||||
cr.Spec.Server.TlsSupport = true
|
||||
cr.Spec.Server.CustomCheProperties = map[string]string{
|
||||
"CHE_WORKSPACE_NO_PROXY": "myproxy.myhostname.com",
|
||||
}
|
||||
cr.Spec.Auth.OpenShiftoAuth = util.NewBoolPointer(true)
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: cr,
|
||||
Proxy: &deploy.Proxy{},
|
||||
ClusterAPI: deploy.ClusterAPI{},
|
||||
}
|
||||
cheEnv, _ := GetCheConfigMapData(deployContext)
|
||||
testCm, _ := deploy.GetSpecConfigMap(deployContext, CheConfigMapName, cheEnv, CheConfigMapName)
|
||||
if testCm.Data["CHE_WORKSPACE_NO_PROXY"] != "myproxy.myhostname.com" {
|
||||
t.Errorf("Test failed. Expected myproxy.myhostname.com but was %s", testCm.Data["CHE_WORKSPACE_NO_PROXY"])
|
||||
util.IsOpenShift = testCase.isOpenShift
|
||||
util.IsOpenShift4 = testCase.isOpenShift4
|
||||
|
||||
actualData, err := GetCheConfigMapData(deployContext)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating ConfigMap data: %v", err)
|
||||
}
|
||||
|
||||
util.ValidateContainData(actualData, testCase.expectedData, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,3 +197,130 @@ func TestConfigMap(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateBitBucketEndpoints(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
initObjects []runtime.Object
|
||||
cheCluster *orgv1.CheCluster
|
||||
expectedData map[string]string
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Test set BitBucket endpoints from secret",
|
||||
initObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "github-oauth-config",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "che.eclipse.org",
|
||||
"app.kubernetes.io/component": "oauth-scm-configuration",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"che.eclipse.org/oauth-scm-server": "bitbucket",
|
||||
"che.eclipse.org/scm-server-endpoint": "bitbucket_endpoint_2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS": "bitbucket_endpoint_2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test update BitBucket endpoints",
|
||||
initObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "github-oauth-config",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "che.eclipse.org",
|
||||
"app.kubernetes.io/component": "oauth-scm-configuration",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"che.eclipse.org/oauth-scm-server": "bitbucket",
|
||||
"che.eclipse.org/scm-server-endpoint": "bitbucket_endpoint_2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CustomCheProperties: map[string]string{
|
||||
"CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS": "bitbucket_endpoint_1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS": "bitbucket_endpoint_1,bitbucket_endpoint_2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test don't update BitBucket endpoints",
|
||||
initObjects: []runtime.Object{},
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CustomCheProperties: map[string]string{
|
||||
"CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS": "bitbucket_endpoint_1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS": "bitbucket_endpoint_1",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.LoggerTo(os.Stdout, true))
|
||||
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
testCase.initObjects = append(testCase.initObjects)
|
||||
cli := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
nonCachedClient := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: testCase.cheCluster,
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
NonCachedClient: nonCachedClient,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
Proxy: &deploy.Proxy{},
|
||||
}
|
||||
|
||||
actualData, err := GetCheConfigMapData(deployContext)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating ConfigMap data: %v", err)
|
||||
}
|
||||
|
||||
util.ValidateContainData(actualData, testCase.expectedData, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
|
@ -273,11 +274,17 @@ func GetSpecCheDeployment(deployContext *deploy.DeployContext) (*appsv1.Deployme
|
|||
},
|
||||
}
|
||||
|
||||
err = MountBitBucketOAuthConfig(deployContext, deployment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
container := &deployment.Spec.Template.Spec.Containers[0]
|
||||
cheMultiUser := deploy.GetCheMultiUser(deployContext.CheCluster)
|
||||
if cheMultiUser == "true" {
|
||||
chePostgresSecret := deployContext.CheCluster.Spec.Database.ChePostgresSecret
|
||||
if len(chePostgresSecret) > 0 {
|
||||
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env,
|
||||
container.Env = append(container.Env,
|
||||
corev1.EnvVar{
|
||||
Name: "CHE_JDBC_USERNAME",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
|
|
@ -311,7 +318,7 @@ func GetSpecCheDeployment(deployContext *deploy.DeployContext) (*appsv1.Deployme
|
|||
},
|
||||
},
|
||||
}}
|
||||
deployment.Spec.Template.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
|
||||
container.VolumeMounts = []corev1.VolumeMount{
|
||||
{
|
||||
MountPath: deploy.DefaultCheVolumeMountPath,
|
||||
Name: deploy.DefaultCheVolumeClaimName,
|
||||
|
|
@ -321,7 +328,7 @@ func GetSpecCheDeployment(deployContext *deploy.DeployContext) (*appsv1.Deployme
|
|||
// configure probes if debug isn't set
|
||||
cheDebug := util.GetValue(deployContext.CheCluster.Spec.Server.CheDebug, deploy.DefaultCheDebug)
|
||||
if cheDebug != "true" {
|
||||
deployment.Spec.Template.Spec.Containers[0].ReadinessProbe = &corev1.Probe{
|
||||
container.ReadinessProbe = &corev1.Probe{
|
||||
Handler: corev1.Handler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
Path: "/api/system/state",
|
||||
|
|
@ -340,7 +347,7 @@ func GetSpecCheDeployment(deployContext *deploy.DeployContext) (*appsv1.Deployme
|
|||
PeriodSeconds: 10,
|
||||
SuccessThreshold: 1,
|
||||
}
|
||||
deployment.Spec.Template.Spec.Containers[0].LivenessProbe = &corev1.Probe{
|
||||
container.LivenessProbe = &corev1.Probe{
|
||||
Handler: corev1.Handler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
Path: "/api/system/state",
|
||||
|
|
@ -406,3 +413,51 @@ func GetFullCheServerImageLink(checluster *orgv1.CheCluster) string {
|
|||
imageParts := strings.Split(defaultCheServerImage, separator)
|
||||
return imageParts[0] + ":" + checluster.Spec.Server.CheImageTag
|
||||
}
|
||||
|
||||
func MountBitBucketOAuthConfig(deployContext *deploy.DeployContext, deployment *appsv1.Deployment) error {
|
||||
// mount BitBucket configuration
|
||||
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
|
||||
}, map[string]string{
|
||||
deploy.CheEclipseOrgOAuthScmServer: "bitbucket",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(secrets) > 1 {
|
||||
return errors.New("More than 1 BitBucket OAuth configuration secrets found")
|
||||
} else if len(secrets) == 1 {
|
||||
// mount secrets
|
||||
container := &deployment.Spec.Template.Spec.Containers[0]
|
||||
deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes,
|
||||
corev1.Volume{
|
||||
Name: secrets[0].Name,
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
Secret: &corev1.SecretVolumeSource{
|
||||
SecretName: secrets[0].Name,
|
||||
},
|
||||
},
|
||||
})
|
||||
container.VolumeMounts = append(container.VolumeMounts,
|
||||
corev1.VolumeMount{
|
||||
Name: secrets[0].Name,
|
||||
MountPath: deploy.BitBucketOAuthConfigMountPath,
|
||||
})
|
||||
|
||||
// mount env
|
||||
endpoint := secrets[0].Annotations[deploy.CheEclipseOrgScmServerEndpoint]
|
||||
container.Env = append(container.Env, corev1.EnvVar{
|
||||
Name: "CHE_OAUTH1_BITBUCKET_CONSUMERKEYPATH",
|
||||
Value: deploy.BitBucketOAuthConfigMountPath + "/" + deploy.BitBucketOAuthConfigConsumerKey,
|
||||
}, corev1.EnvVar{
|
||||
Name: "CHE_OAUTH1_BITBUCKET_PRIVATEKEYPATH",
|
||||
Value: deploy.BitBucketOAuthConfigMountPath + "/" + deploy.BitBucketOAuthConfigPrivateKey,
|
||||
}, corev1.EnvVar{
|
||||
Name: "CHE_OAUTH1_BITBUCKET_ENDPOINT",
|
||||
Value: endpoint,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,15 @@ package server
|
|||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/eclipse/che-operator/pkg/util"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/eclipse/che-operator/pkg/deploy"
|
||||
|
||||
orgv1 "github.com/eclipse/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/client-go/kubernetes/scheme"
|
||||
|
|
@ -110,3 +113,124 @@ func TestDeployment(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountBitBucketOAuthEnvVar(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
initObjects []runtime.Object
|
||||
cheCluster *orgv1.CheCluster
|
||||
expectedConsumerKeyPathEnv corev1.EnvVar
|
||||
expectedPrivateKeyPathEnv corev1.EnvVar
|
||||
expectedEndpointEnv corev1.EnvVar
|
||||
expectedVolume corev1.Volume
|
||||
expectedVolumeMount corev1.VolumeMount
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Test",
|
||||
initObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "github-oauth-config",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "che.eclipse.org",
|
||||
"app.kubernetes.io/component": "oauth-scm-configuration",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"che.eclipse.org/oauth-scm-server": "bitbucket",
|
||||
"che.eclipse.org/scm-server-endpoint": "bitbucket_endpoint",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"private.key": []byte("private_key"),
|
||||
"consumer.key": []byte("consumer_key"),
|
||||
},
|
||||
},
|
||||
},
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
},
|
||||
expectedConsumerKeyPathEnv: corev1.EnvVar{
|
||||
Name: "CHE_OAUTH1_BITBUCKET_CONSUMERKEYPATH",
|
||||
Value: "/che-conf/oauth/bitbucket/consumer.key",
|
||||
},
|
||||
expectedPrivateKeyPathEnv: corev1.EnvVar{
|
||||
Name: "CHE_OAUTH1_BITBUCKET_PRIVATEKEYPATH",
|
||||
Value: "/che-conf/oauth/bitbucket/private.key",
|
||||
},
|
||||
expectedEndpointEnv: corev1.EnvVar{
|
||||
Name: "CHE_OAUTH1_BITBUCKET_ENDPOINT",
|
||||
Value: "bitbucket_endpoint",
|
||||
},
|
||||
expectedVolume: corev1.Volume{
|
||||
Name: "github-oauth-config",
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
Secret: &corev1.SecretVolumeSource{
|
||||
SecretName: "github-oauth-config",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedVolumeMount: corev1.VolumeMount{
|
||||
Name: "github-oauth-config",
|
||||
MountPath: "/che-conf/oauth/bitbucket",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.LoggerTo(os.Stdout, true))
|
||||
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
testCase.initObjects = append(testCase.initObjects)
|
||||
cli := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: testCase.cheCluster,
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
Proxy: &deploy.Proxy{},
|
||||
}
|
||||
|
||||
deployment, err := GetSpecCheDeployment(deployContext)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating deployment: %v", err)
|
||||
}
|
||||
|
||||
container := &deployment.Spec.Template.Spec.Containers[0]
|
||||
env := util.FindEnv(container.Env, "CHE_OAUTH1_BITBUCKET_CONSUMERKEYPATH")
|
||||
if !reflect.DeepEqual(testCase.expectedConsumerKeyPathEnv, *env) {
|
||||
t.Errorf("Expected Env and Env returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedConsumerKeyPathEnv, env))
|
||||
}
|
||||
|
||||
env = util.FindEnv(container.Env, "CHE_OAUTH1_BITBUCKET_PRIVATEKEYPATH")
|
||||
if !reflect.DeepEqual(testCase.expectedPrivateKeyPathEnv, *env) {
|
||||
t.Errorf("Expected Env and Env returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedPrivateKeyPathEnv, env))
|
||||
}
|
||||
|
||||
env = util.FindEnv(container.Env, "CHE_OAUTH1_BITBUCKET_ENDPOINT")
|
||||
if !reflect.DeepEqual(testCase.expectedEndpointEnv, *env) {
|
||||
t.Errorf("Expected Env and Env returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedEndpointEnv, env))
|
||||
}
|
||||
|
||||
volume := util.FindVolume(deployment.Spec.Template.Spec.Volumes, "github-oauth-config")
|
||||
if !reflect.DeepEqual(testCase.expectedVolume, volume) {
|
||||
t.Errorf("Expected Volume and Volume returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedVolume, volume))
|
||||
}
|
||||
|
||||
volumeMount := util.FindVolumeMount(container.VolumeMounts, "github-oauth-config")
|
||||
if !reflect.DeepEqual(testCase.expectedVolumeMount, volumeMount) {
|
||||
t.Errorf("Expected VolumeMount and VolumeMount returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedVolumeMount, volumeMount))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
"testing"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
)
|
||||
|
||||
|
|
@ -26,30 +27,31 @@ type TestExpectedResources struct {
|
|||
}
|
||||
|
||||
func CompareResources(actualDeployment *appsv1.Deployment, expected TestExpectedResources, t *testing.T) {
|
||||
container := &actualDeployment.Spec.Template.Spec.Containers[0]
|
||||
compareQuantity(
|
||||
"Memory limits",
|
||||
actualDeployment.Spec.Template.Spec.Containers[0].Resources.Limits.Memory(),
|
||||
container.Resources.Limits.Memory(),
|
||||
expected.MemoryLimit,
|
||||
t,
|
||||
)
|
||||
|
||||
compareQuantity(
|
||||
"Memory requests",
|
||||
actualDeployment.Spec.Template.Spec.Containers[0].Resources.Requests.Memory(),
|
||||
container.Resources.Requests.Memory(),
|
||||
expected.MemoryRequest,
|
||||
t,
|
||||
)
|
||||
|
||||
compareQuantity(
|
||||
"CPU limits",
|
||||
actualDeployment.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu(),
|
||||
container.Resources.Limits.Cpu(),
|
||||
expected.CpuLimit,
|
||||
t,
|
||||
)
|
||||
|
||||
compareQuantity(
|
||||
"CPU requests",
|
||||
actualDeployment.Spec.Template.Spec.Containers[0].Resources.Requests.Cpu(),
|
||||
container.Resources.Requests.Cpu(),
|
||||
expected.CpuRequest,
|
||||
t,
|
||||
)
|
||||
|
|
@ -80,3 +82,23 @@ func ValidateContainData(actualData map[string]string, expectedData map[string]s
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func FindVolume(volumes []corev1.Volume, name string) corev1.Volume {
|
||||
for _, volume := range volumes {
|
||||
if volume.Name == name {
|
||||
return volume
|
||||
}
|
||||
}
|
||||
|
||||
return corev1.Volume{}
|
||||
}
|
||||
|
||||
func FindVolumeMount(volumes []corev1.VolumeMount, name string) corev1.VolumeMount {
|
||||
for _, volumeMount := range volumes {
|
||||
if volumeMount.Name == name {
|
||||
return volumeMount
|
||||
}
|
||||
}
|
||||
|
||||
return corev1.VolumeMount{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,3 +410,14 @@ func GetResourceQuantity(value string, defaultValue string) resource.Quantity {
|
|||
}
|
||||
return resource.MustParse(defaultValue)
|
||||
}
|
||||
|
||||
// Finds Env by a given name
|
||||
func FindEnv(envs []corev1.EnvVar, name string) *corev1.EnvVar {
|
||||
for _, env := range envs {
|
||||
if env.Name == name {
|
||||
return &env
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue