chore: Remove obsolete code after switching to Dev Workspace enabled (#1291)
* chore: Remove keycloak deployment Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Get rid of codebase related to spec.devWorkspace.enable field Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove code related to auth.initialOpenShiftOAuthUser field Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove code related to some auth.* fields Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove code related to some auth.openShiftoAuth field Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove code related to auth.nativeUserMode field Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove code related to server.tlsSupport and server.*ClusterSVCNames fields Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Update bundle Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove code related to server expouse strategy fields Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove deprecated code Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Remove code related to server.tlsSupport and server.cheFlavor field Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Update bundle Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Update helm charts Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: Update bundle Signed-off-by: Anatolii Bazko <abazko@redhat.com> * chore: remove RELATED_IMAGE_keycloak Signed-off-by: Anatolii Bazko <abazko@redhat.com>7.41
parent
228a3350cd
commit
92d24388ec
5
Makefile
5
Makefile
|
|
@ -254,7 +254,7 @@ vet: ## Run go vet against code.
|
|||
go vet ./...
|
||||
|
||||
ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
|
||||
test: manifests generate fmt vet prepare-templates ## Run tests.
|
||||
test: prepare-templates ## Run tests.
|
||||
export MOCK_API=true; go test -mod=vendor ./... -coverprofile cover.out
|
||||
|
||||
##@ Build
|
||||
|
|
@ -664,8 +664,9 @@ get-next-version-increment:
|
|||
echo "$${incrementPart}"
|
||||
|
||||
update-resources: SHELL := /bin/bash
|
||||
update-resources: check-requirements update-resource-images update-roles update-helmcharts
|
||||
update-resources: check-requirements update-resource-images update-roles
|
||||
$(MAKE) bundle channel=next
|
||||
$(MAKE) update-helmcharts HELM_FOLDER=next
|
||||
|
||||
update-helmcharts: SHELL := /bin/bash
|
||||
update-helmcharts: add-license-download check-requirements
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -201,28 +201,6 @@ spec:
|
|||
```bash
|
||||
$ chectl server:update -n <ECLIPSE-CHE-NAMESPACE> --che-operator-cr-patch-yaml <PATH_TO_CR_PATCH_YAML>
|
||||
|
||||
### OpenShift OAuth
|
||||
|
||||
OpenShift clusters include a built-in OAuth server. Che operator supports this authentication method. It's enabled by default.
|
||||
|
||||
To disable OpenShift OAuth use command line:
|
||||
|
||||
```bash
|
||||
$ kubectl patch checluster/eclipse-che -n <ECLIPSE-CHE-NAMESPACE> --type=merge -p '{"spec":{"auth":{"openShiftoAuth": false}}}'
|
||||
```
|
||||
|
||||
or create `cr-patch.yaml` and use it with chectl:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
auth:
|
||||
openShiftoAuth: false
|
||||
```
|
||||
|
||||
```bash
|
||||
$ chectl server:update -n <ECLIPSE-CHE-NAMESPACE> --che-operator-cr-patch-yaml <PATH_TO_CR_PATCH_YAML>
|
||||
```
|
||||
|
||||
### TLS
|
||||
|
||||
TLS is enabled by default.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/eclipse-che/che-operator/api/v2alpha1"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"k8s.io/utils/pointer"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
|
|
@ -104,7 +105,6 @@ func V2alpha1ToV1(v2 *v2alpha1.CheCluster, v1Obj *v1.CheCluster) error {
|
|||
|
||||
v2alpha1ToV1_Enabled(v1Obj, v2)
|
||||
v2alpha1ToV1_Host(v1Obj, v2)
|
||||
v2alpha1ToV1_GatewayEnabled(v1Obj, v2)
|
||||
v2alpha1ToV1_GatewayImage(v1Obj, v2)
|
||||
v2alpha1ToV1_GatewayConfigurerImage(v1Obj, v2)
|
||||
v2alpha1ToV1_GatewayTlsSecretName(v1Obj, v2)
|
||||
|
|
@ -145,7 +145,6 @@ func v1ToV2alpha1_WorkspaceDomainEndpointsTlsSecretName(v1 *v1.CheCluster, v2 *v
|
|||
}
|
||||
|
||||
func v1ToV2alpha1_GatewayEnabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
|
||||
exposureStrategy := util.GetServerExposureStrategy(v1)
|
||||
// On Kubernetes, we can have single-host realized using ingresses (that use the same host but different paths).
|
||||
// This is actually not supported on DWCO where we always use the gateway for that. So here, we actually just
|
||||
// ignore the Spec.K8s.SingleHostExposureType, but we need to be aware of it when converting back.
|
||||
|
|
@ -153,8 +152,7 @@ func v1ToV2alpha1_GatewayEnabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
|
|||
// treat it as such for v2. The difference between default-host and single-host is that the default-host uses
|
||||
// the cluster domain itself as the base domain whereas single-host uses a configured domain. In v2 we always
|
||||
// need a domain configured.
|
||||
val := exposureStrategy == "single-host" || exposureStrategy == "default-host"
|
||||
v2.Spec.Gateway.Enabled = &val
|
||||
v2.Spec.Gateway.Enabled = pointer.BoolPtr(true)
|
||||
}
|
||||
|
||||
func v1ToV2alpha1_GatewayImage(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
|
||||
|
|
@ -184,11 +182,6 @@ func v1ToV2alpha1_K8sIngressAnnotations(v1 *v1.CheCluster, v2 *v2alpha1.CheClust
|
|||
}
|
||||
v2.Spec.K8s.IngressAnnotations["kubernetes.io/ingress.class"] = v1.Spec.K8s.IngressClass
|
||||
}
|
||||
|
||||
// This is what is applied in the deploy/ingress.go but I don't think it is applicable in our situation
|
||||
// if ingressStrategy != "multi-host" && (component == DevfileRegistryName || component == PluginRegistryName) {
|
||||
// annotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$1"
|
||||
// }
|
||||
}
|
||||
|
||||
func v2alpha1ToV1_Enabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
|
||||
|
|
@ -219,70 +212,6 @@ func v2alpha1ToV1_WorkspaceDomainEndpointsTlsSecretName(v1 *v1.CheCluster, v2 *v
|
|||
}
|
||||
}
|
||||
|
||||
func v2alpha1ToV1_GatewayEnabled(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
|
||||
v1Strategy := util.GetServerExposureStrategy(v1)
|
||||
v1IngressStrategy := v1.Spec.K8s.IngressStrategy
|
||||
|
||||
var v2Strategy string
|
||||
if v2.Spec.Gateway.IsEnabled() {
|
||||
v2Strategy = "single-host"
|
||||
} else {
|
||||
v2Strategy = "multi-host"
|
||||
}
|
||||
|
||||
if v1.Spec.Server.ServerExposureStrategy == "" {
|
||||
// in the original, the server exposure strategy was undefined, so we need to check whether we can leave it that way
|
||||
if util.IsOpenShift {
|
||||
if v2Strategy != v1Strategy {
|
||||
// only update if the v2Strategy doesn't correspond to the default determined from the v1
|
||||
v1.Spec.Server.ServerExposureStrategy = v2Strategy
|
||||
}
|
||||
} else {
|
||||
// on Kubernetes, the strategy might have been defined by the deprecated Spec.K8s.IngressStrategy
|
||||
if v1IngressStrategy != "" {
|
||||
// check for the default host
|
||||
if v1IngressStrategy == "default-host" {
|
||||
if v2Strategy != "single-host" {
|
||||
v1.Spec.K8s.IngressStrategy = v2Strategy
|
||||
}
|
||||
} else if v2Strategy != v1Strategy {
|
||||
// only change the strategy if the determined strategy would differ
|
||||
v1.Spec.K8s.IngressStrategy = v2Strategy
|
||||
}
|
||||
} else {
|
||||
if v2Strategy != v1Strategy {
|
||||
// only update if the v2Strategy doesn't correspond to the default determined from the v1
|
||||
v1.Spec.Server.ServerExposureStrategy = v2Strategy
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The below table specifies how to convert the v2Strategy back to v1 taking into the account the original state of v1
|
||||
// from which v2 was converted before (which could also be just the default v1, if v2 was created on its own)
|
||||
//
|
||||
// v2Strategy | orig v1Strategy | orig v1ExposureType | resulting v1Strategy | resulting v1ExposureType
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// single | single | native | single | orig
|
||||
// single | single | gateway | single | orig
|
||||
// single | default | NA | default | orig
|
||||
// single | multi | NA | single | orig
|
||||
// multi | single | native | multi | orig
|
||||
// multi | single | gateway | multi | orig
|
||||
// multi | default | NA | multi | orig
|
||||
// multi | multi | NA | multi | orig
|
||||
//
|
||||
// Notice that we don't ever want to update the singlehost exposure type. This is only used on Kubernetes and dictates how
|
||||
// we are going to expose the singlehost endpoints - either using ingresses (native) or using the gateway.
|
||||
// Because this distinction is not made in DWCO, which always uses the gateway, we just keep whatever the value was originally.
|
||||
//
|
||||
// The default-host is actually not supported in v2... but it is quite similar to single host in that everything is exposed
|
||||
// through the cluster hostname and when converting to v2, we convert it to single-host
|
||||
if v1Strategy != "default-host" || v2Strategy != "single-host" {
|
||||
v1.Spec.Server.ServerExposureStrategy = v2Strategy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func v2alpha1ToV1_GatewayImage(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) {
|
||||
v1.Spec.Server.SingleHostGatewayImage = v2.Spec.Gateway.Image
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
package org
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
|
@ -54,10 +53,9 @@ func TestV1ToV2alpha1(t *testing.T) {
|
|||
},
|
||||
},
|
||||
K8s: v1.CheClusterSpecK8SOnly{
|
||||
IngressDomain: "ingressDomain",
|
||||
IngressClass: "traefik",
|
||||
TlsSecretName: "k8sSecret",
|
||||
IngressStrategy: "single-host",
|
||||
IngressDomain: "ingressDomain",
|
||||
IngressClass: "traefik",
|
||||
TlsSecretName: "k8sSecret",
|
||||
},
|
||||
Metrics: v1.CheClusterSpecMetrics{
|
||||
Enable: true,
|
||||
|
|
@ -207,8 +205,8 @@ func TestV1ToV2alpha1(t *testing.T) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
if *v2.Spec.Gateway.Enabled {
|
||||
t.Errorf("The default for OpenShift without devworkspace enabled (which is our testing object) is multihost, but we found v2 in singlehost.")
|
||||
if !*v2.Spec.Gateway.Enabled {
|
||||
t.Errorf("The default for OpenShift is single")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -418,11 +416,6 @@ func TestV2alpha1ToV1(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if util.GetServerExposureStrategy(v1) != "single-host" {
|
||||
t.Logf("When gateway.enabled is true in v2, v1 is single-host.")
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -463,180 +456,6 @@ func TestV2alpha1ToV1(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestExposureStrategyConversions(t *testing.T) {
|
||||
testWithExposure := func(v1ExposureStrategy string, v1IngressStrategy string, v1DevWorkspaceEnabled bool, v2GatewayEnabledChange *bool, test func(*testing.T, *v1.CheCluster)) {
|
||||
origV1 := &v1.CheCluster{
|
||||
Spec: v1.CheClusterSpec{
|
||||
Server: v1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: v1ExposureStrategy,
|
||||
},
|
||||
K8s: v1.CheClusterSpecK8SOnly{
|
||||
IngressStrategy: v1IngressStrategy,
|
||||
},
|
||||
DevWorkspace: v1.CheClusterSpecDevWorkspace{
|
||||
Enable: v1DevWorkspaceEnabled,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("[v1ExposureStrategy=%v/v1IngressStrategy=%v/v1DevworkspaceEnabled=%v/v2GatewayEnabledChange=%v]", v1ExposureStrategy, v1IngressStrategy, v1DevWorkspaceEnabled, v2GatewayEnabledChange), func(t *testing.T) {
|
||||
v2 := &v2alpha1.CheCluster{}
|
||||
if err := V1ToV2alpha1(origV1, v2); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if v2GatewayEnabledChange != nil {
|
||||
v2.Spec.Gateway.Enabled = v2GatewayEnabledChange
|
||||
}
|
||||
|
||||
// now convert back and run the test
|
||||
v1Tested := &v1.CheCluster{}
|
||||
if err := V2alpha1ToV1(v2, v1Tested); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
test(t, v1Tested)
|
||||
})
|
||||
}
|
||||
|
||||
testWithExposure("single-host", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "single-host" {
|
||||
t.Errorf("The v1 should have single-host exposure after conversion")
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("single-host", "", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
|
||||
t.Errorf("The v1 should have multi-host exposure after conversion")
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("multi-host", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
|
||||
t.Errorf("The v1 should have multi-host exposure after conversion")
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("multi-host", "", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "single-host" {
|
||||
t.Errorf("The v1 should have single-host exposure after conversion")
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("default-host", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "default-host" {
|
||||
t.Errorf("The v1 should have default-host exposure after conversion")
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("default-host", "", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "default-host" {
|
||||
t.Errorf("The v1 should have default-host exposure after conversion")
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("default-host", "", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
|
||||
t.Errorf("The v1 should have multi-host exposure after conversion")
|
||||
}
|
||||
})
|
||||
|
||||
onFakeKubernetes(func() {
|
||||
testWithExposure("", "single-host", true, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
if old.Spec.K8s.IngressStrategy != "single-host" {
|
||||
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "single-host", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
if old.Spec.K8s.IngressStrategy != "multi-host" {
|
||||
t.Errorf("The ingress strategy should have been set to multi-host after conversion but was: %v", old.Spec.K8s.IngressStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "single-host", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
if old.Spec.K8s.IngressStrategy != "single-host" {
|
||||
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "multi-host", true, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
if old.Spec.K8s.IngressStrategy != "multi-host" {
|
||||
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
// the below two tests test that we're leaving the ingress strategy unchanged if it doesn't affect the effective exposure
|
||||
// strategy
|
||||
testWithExposure("", "multi-host", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
if old.Spec.K8s.IngressStrategy != "multi-host" {
|
||||
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "multi-host", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
if old.Spec.K8s.IngressStrategy != "single-host" {
|
||||
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "default-host", true, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
if old.Spec.K8s.IngressStrategy != "default-host" {
|
||||
t.Errorf("The ingress strategy should have been unchanged after conversion but was: %v", old.Spec.K8s.IngressStrategy)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onFakeOpenShift(func() {
|
||||
testWithExposure("", "", true, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "", false, nil, func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "", true, pointer.BoolPtr(false), func(t *testing.T, old *v1.CheCluster) {
|
||||
// default on openshift with devworkspace enabled in v1 is single-host, but we've disabled the gateway in v2. So after the conversion
|
||||
// v1 should change to an explicit multi-host.
|
||||
if old.Spec.Server.ServerExposureStrategy != "multi-host" {
|
||||
t.Errorf("The server exposure strategy should have been set to multi-host after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
})
|
||||
|
||||
testWithExposure("", "", true, pointer.BoolPtr(true), func(t *testing.T, old *v1.CheCluster) {
|
||||
if old.Spec.Server.ServerExposureStrategy != "" {
|
||||
t.Errorf("The server exposure strategy should have been left empty after conversion but was: %v", old.Spec.Server.ServerExposureStrategy)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFullCircleV1(t *testing.T) {
|
||||
v1Obj := v1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
|
@ -661,10 +480,9 @@ func TestFullCircleV1(t *testing.T) {
|
|||
},
|
||||
},
|
||||
K8s: v1.CheClusterSpecK8SOnly{
|
||||
IngressDomain: "ingressDomain",
|
||||
IngressClass: "traefik",
|
||||
TlsSecretName: "k8sSecret",
|
||||
IngressStrategy: "single-host",
|
||||
IngressDomain: "ingressDomain",
|
||||
IngressClass: "traefik",
|
||||
TlsSecretName: "k8sSecret",
|
||||
},
|
||||
Metrics: v1.CheClusterSpecMetrics{
|
||||
Enable: true,
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ type CheClusterSpecServer struct {
|
|||
// Default value is `Always` for `nightly`, `next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
// +optional
|
||||
CheImagePullPolicy corev1.PullPolicy `json:"cheImagePullPolicy,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Specifies a variation of the installation. The options are `che` for upstream Che installations, or `codeready` for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady Workspaces] installation.
|
||||
// Override the default value only on necessary occasions.
|
||||
// +optional
|
||||
|
|
@ -158,6 +159,7 @@ type CheClusterSpecServer struct {
|
|||
// +optional
|
||||
// +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden"
|
||||
UseInternalClusterSVCNames bool `json:"useInternalClusterSVCNames"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Disable internal cluster SVC names usage to communicate between components to speed up the traffic and avoid proxy issues.
|
||||
// +optional
|
||||
DisableInternalClusterSVCNames *bool `json:"disableInternalClusterSVCNames,omitempty"`
|
||||
|
|
@ -183,9 +185,11 @@ type CheClusterSpecServer struct {
|
|||
// In cores. (500m = .5 cores). Default to 100m.
|
||||
// +optional
|
||||
DashboardCpuRequest string `json:"dashboardCpuRequest,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Dashboard ingress custom settings.
|
||||
// +optional
|
||||
DashboardIngress IngressCustomSettings `json:"dashboardIngress,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Dashboard route custom settings.
|
||||
// +optional
|
||||
DashboardRoute RouteCustomSettings `json:"dashboardRoute,omitempty"`
|
||||
|
|
@ -215,9 +219,11 @@ type CheClusterSpecServer struct {
|
|||
// In cores. (500m = .5 cores). Default to 100m.
|
||||
// +optional
|
||||
DevfileRegistryCpuRequest string `json:"devfileRegistryCpuRequest,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// The devfile registry ingress custom settings.
|
||||
// +optional
|
||||
DevfileRegistryIngress IngressCustomSettings `json:"devfileRegistryIngress,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// The devfile registry route custom settings.
|
||||
// +optional
|
||||
DevfileRegistryRoute RouteCustomSettings `json:"devfileRegistryRoute,omitempty"`
|
||||
|
|
@ -259,9 +265,11 @@ type CheClusterSpecServer struct {
|
|||
// In cores. (500m = .5 cores). Default to 100m.
|
||||
// +optional
|
||||
PluginRegistryCpuRequest string `json:"pluginRegistryCpuRequest,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Plugin registry ingress custom settings.
|
||||
// +optional
|
||||
PluginRegistryIngress IngressCustomSettings `json:"pluginRegistryIngress,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Plugin registry route custom settings.
|
||||
// +optional
|
||||
PluginRegistryRoute RouteCustomSettings `json:"pluginRegistryRoute,omitempty"`
|
||||
|
|
@ -318,6 +326,7 @@ type CheClusterSpecServer struct {
|
|||
// In cores. (500m = .5 cores). Default to 100m.
|
||||
// +optional
|
||||
ServerCpuRequest string `json:"serverCpuRequest,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Sets the server and workspaces exposure type.
|
||||
// Possible values are `multi-host`, `single-host`, `default-host`. Defaults to `multi-host`, which creates a separate ingress, or OpenShift routes, for every required endpoint.
|
||||
// `single-host` makes Che exposed on a single host name with workspaces exposed on subpaths.
|
||||
|
|
@ -403,6 +412,7 @@ type CheClusterSpecDB struct {
|
|||
// +k8s:openapi-gen=true
|
||||
// Configuration settings related to the Authentication used by the Che installation.
|
||||
type CheClusterSpecAuth struct {
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// For operating with the OpenShift OAuth authentication, create a new user account since the kubeadmin can not be used.
|
||||
// If the value is true, then a new OpenShift OAuth user will be created for the HTPasswd identity provider.
|
||||
// If the value is false and the user has already been created, then it will be removed.
|
||||
|
|
@ -410,6 +420,7 @@ type CheClusterSpecAuth struct {
|
|||
// The user's credentials are stored in the `openshift-oauth-user-credentials` secret in 'openshift-config' namespace by Operator.
|
||||
// Note that this solution is Openshift 4 platform-specific.
|
||||
InitialOpenShiftOAuthUser *bool `json:"initialOpenShiftOAuthUser,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Instructs the Operator on whether or not to deploy a dedicated Identity Provider (Keycloak or RH SSO instance).
|
||||
// Instructs the Operator on whether to deploy a dedicated Identity Provider (Keycloak or RH-SSO instance).
|
||||
// By default, a dedicated Identity Provider server is deployed as part of the Che installation. When `externalIdentityProvider` is `true`,
|
||||
|
|
@ -422,14 +433,17 @@ type CheClusterSpecAuth struct {
|
|||
// See the `externalIdentityProvider` field. By default, this will be automatically calculated and set by the Operator.
|
||||
// +optional
|
||||
IdentityProviderURL string `json:"identityProviderURL,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Overrides the name of the Identity Provider administrator user. Defaults to `admin`.
|
||||
// +optional
|
||||
IdentityProviderAdminUserName string `json:"identityProviderAdminUserName,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Overrides the password of Keycloak administrator user.
|
||||
// Override this when an external Identity Provider is in use. See the `externalIdentityProvider` field.
|
||||
// When omitted or left blank, it is set to an auto-generated password.
|
||||
// +optional
|
||||
IdentityProviderPassword string `json:"identityProviderPassword,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// The secret that contains `user` and `password` for Identity Provider.
|
||||
// When the secret is defined, the `identityProviderAdminUserName` and `identityProviderPassword` are ignored.
|
||||
// When the value is omitted or left blank, the one of following scenarios applies:
|
||||
|
|
@ -439,21 +453,25 @@ type CheClusterSpecAuth struct {
|
|||
// The secret must have `app.kubernetes.io/part-of=che.eclipse.org` label.
|
||||
// +optional
|
||||
IdentityProviderSecret string `json:"identityProviderSecret,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Name of a Identity provider, Keycloak or RH-SSO, realm that is used for Che.
|
||||
// Override this when an external Identity Provider is in use. See the `externalIdentityProvider` field.
|
||||
// When omitted or left blank, it is set to the value of the `flavour` field.
|
||||
// +optional
|
||||
IdentityProviderRealm string `json:"identityProviderRealm,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Name of a Identity provider, Keycloak or RH-SSO, `client-id` that is used for Che.
|
||||
// Override this when an external Identity Provider is in use. See the `externalIdentityProvider` field.
|
||||
// When omitted or left blank, it is set to the value of the `flavour` field suffixed with `-public`.
|
||||
// +optional
|
||||
IdentityProviderClientId string `json:"identityProviderClientId,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Password for a Identity Provider, Keycloak or RH-SSO, to connect to the database.
|
||||
// Override this when an external Identity Provider is in use. See the `externalIdentityProvider` field.
|
||||
// When omitted or left blank, it is set to an auto-generated password.
|
||||
// +optional
|
||||
IdentityProviderPostgresPassword string `json:"identityProviderPostgresPassword,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// The secret that contains `password` for the Identity Provider, Keycloak or RH-SSO, to connect to the database.
|
||||
// When the secret is defined, the `identityProviderPostgresPassword` is ignored. When the value is omitted or left blank, the one of following scenarios applies:
|
||||
// 1. `identityProviderPostgresPassword` is defined, then it will be used to connect to the database.
|
||||
|
|
@ -461,9 +479,11 @@ type CheClusterSpecAuth struct {
|
|||
// The secret must have `app.kubernetes.io/part-of=che.eclipse.org` label.
|
||||
// +optional
|
||||
IdentityProviderPostgresSecret string `json:"identityProviderPostgresSecret,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Forces the default `admin` Che user to update password on first login. Defaults to `false`.
|
||||
// +optional
|
||||
UpdateAdminPassword bool `json:"updateAdminPassword"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Enables the integration of the identity provider (Keycloak / RHSSO) with OpenShift OAuth.
|
||||
// Empty value on OpenShift by default. This will allow users to directly login with their OpenShift user through the OpenShift login,
|
||||
// and have their workspaces created under personal OpenShift namespaces.
|
||||
|
|
@ -476,23 +496,29 @@ type CheClusterSpecAuth struct {
|
|||
// Name of the secret set in the OpenShift `OAuthClient` resource used to setup identity federation on the OpenShift side. Auto-generated when left blank. See also the `OAuthClientName` field.
|
||||
// +optional
|
||||
OAuthSecret string `json:"oAuthSecret,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Overrides the container image used in the Identity Provider, Keycloak or RH-SSO, deployment.
|
||||
// This includes the image tag. Omit it or leave it empty to use the default container image provided by the Operator.
|
||||
// +optional
|
||||
IdentityProviderImage string `json:"identityProviderImage,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Overrides the image pull policy used in the Identity Provider, Keycloak or RH-SSO, deployment.
|
||||
// Default value is `Always` for `nightly`, `next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
// +optional
|
||||
IdentityProviderImagePullPolicy corev1.PullPolicy `json:"identityProviderImagePullPolicy,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Ingress custom settings.
|
||||
// +optional
|
||||
IdentityProviderIngress IngressCustomSettings `json:"identityProviderIngress,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Route custom settings.
|
||||
// +optional
|
||||
IdentityProviderRoute RouteCustomSettings `json:"identityProviderRoute,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Identity provider container custom settings.
|
||||
// +optional
|
||||
IdentityProviderContainerResources ResourcesCustomSettings `json:"identityProviderContainerResources,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Enables native user mode. Currently works only on OpenShift and DevWorkspace engine.
|
||||
// Native User mode uses OpenShift OAuth directly as identity provider, without Keycloak.
|
||||
// +optional
|
||||
|
|
@ -509,7 +535,7 @@ type CheClusterSpecAuth struct {
|
|||
// +optional
|
||||
// +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden"
|
||||
GatewayHeaderRewriteSidecarImage string `json:"gatewayHeaderRewriteSidecarImage,omitempty"`
|
||||
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Debug internal identity provider.
|
||||
Debug bool `json:"debug,omitempty"`
|
||||
}
|
||||
|
|
@ -597,6 +623,7 @@ type CheClusterSpecStorage struct {
|
|||
type CheClusterSpecK8SOnly struct {
|
||||
// Global ingress domain for a Kubernetes cluster. This MUST be explicitly specified: there are no defaults.
|
||||
IngressDomain string `json:"ingressDomain,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// Strategy for ingress creation. Options are: `multi-host` (host is explicitly provided in ingress),
|
||||
// `single-host` (host is provided, path-based rules) and `default-host` (no host is provided, path-based rules).
|
||||
// Defaults to `multi-host` Deprecated in favor of `serverExposureStrategy` in the `server` section,
|
||||
|
|
@ -617,6 +644,7 @@ type CheClusterSpecK8SOnly struct {
|
|||
// ID of the user the Che Pod and workspace Pods containers run as. Default value is `1724`.
|
||||
// +optional
|
||||
SecurityContextRunAsUser string `json:"securityContextRunAsUser,omitempty"`
|
||||
// Deprecated. The value of this flag is ignored.
|
||||
// When the serverExposureStrategy is set to `single-host`, the way the server, registries and workspaces are exposed is further configured by this property.
|
||||
// The possible values are `native`, which means that the server and workspaces are exposed using ingresses on K8s
|
||||
// or `gateway` where the server and workspaces are exposed using a custom gateway based on link:https://doc.traefik.io/traefik/[Traefik].
|
||||
|
|
@ -746,7 +774,6 @@ type CheClusterStatus struct {
|
|||
// +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Help link"
|
||||
// +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors="urn:alm:descriptor:org.w3:link"
|
||||
HelpLink string `json:"helpLink,omitempty"`
|
||||
|
||||
// The status of the Devworkspace subsystem
|
||||
// +optional
|
||||
DevworkspaceStatus v2alpha1.CheClusterStatusV2Alpha1 `json:"devworkspaceStatus,omitempty"`
|
||||
|
|
@ -800,24 +827,3 @@ func (c *CheCluster) IsImagePullerSpecEmpty() bool {
|
|||
func (c *CheCluster) IsImagePullerImagesEmpty() bool {
|
||||
return len(c.Spec.ImagePuller.Spec.Images) == 0
|
||||
}
|
||||
|
||||
func (c *CheCluster) IsInternalClusterSVCNamesEnabled() bool {
|
||||
return c.Spec.Server.DisableInternalClusterSVCNames == nil || !*c.Spec.Server.DisableInternalClusterSVCNames
|
||||
}
|
||||
|
||||
// IsInitialOpenShiftOAuthUserEnabled returns true when initial Openshift oAuth user is enabled for CheCluster resource, otherwise false.
|
||||
func (c *CheCluster) IsOpenShiftOAuthUserConfigured() bool {
|
||||
return c.Spec.Auth.InitialOpenShiftOAuthUser != nil && *c.Spec.Auth.InitialOpenShiftOAuthUser
|
||||
}
|
||||
|
||||
func (c *CheCluster) IsOpenShiftOAuthUserMustBeDeleted() bool {
|
||||
return c.Spec.Auth.InitialOpenShiftOAuthUser != nil && !*c.Spec.Auth.InitialOpenShiftOAuthUser
|
||||
}
|
||||
|
||||
func (c *CheCluster) IsOpenShiftOAuthEnabled() bool {
|
||||
return c.Spec.Auth.OpenShiftoAuth != nil && *c.Spec.Auth.OpenShiftoAuth
|
||||
}
|
||||
|
||||
func (c *CheCluster) IsNativeUserModeEnabled() bool {
|
||||
return c.Spec.Auth.NativeUserMode != nil && *c.Spec.Auth.NativeUserMode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ metadata:
|
|||
"proxyPort": "",
|
||||
"proxySecret": "",
|
||||
"proxyURL": "",
|
||||
"tlsSupport": true,
|
||||
"workspaceNamespaceDefault": "<username>-che"
|
||||
},
|
||||
"storage": {
|
||||
|
|
@ -114,7 +113,7 @@ metadata:
|
|||
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
|
||||
repository: https://github.com/eclipse-che/che-operator
|
||||
support: Eclipse Foundation
|
||||
name: eclipse-che-preview-openshift.v7.43.0-408.next
|
||||
name: eclipse-che-preview-openshift.v7.43.0-412.next
|
||||
namespace: placeholder
|
||||
spec:
|
||||
apiservicedefinitions: {}
|
||||
|
|
@ -1079,8 +1078,6 @@ spec:
|
|||
value: quay.io/eclipse/che--centos--postgresql-96-centos7:9.6-b681d78125361519180a6ac05242c296f8906c11eab7e207b5ca9a89b6344392
|
||||
- name: RELATED_IMAGE_postgres_13_3
|
||||
value: quay.io/eclipse/che--centos--postgresql-13-centos7:1-71b24684d64da46f960682cc4216222a7e4ed8b1a31dd5a865b3e71afdea20d2
|
||||
- name: RELATED_IMAGE_keycloak
|
||||
value: quay.io/eclipse/che-keycloak:next
|
||||
- name: RELATED_IMAGE_che_workspace_plugin_broker_metadata
|
||||
value: quay.io/eclipse/che-plugin-metadata-broker:v3.4.0
|
||||
- name: RELATED_IMAGE_che_workspace_plugin_broker_artifacts
|
||||
|
|
@ -1406,4 +1403,4 @@ spec:
|
|||
maturity: stable
|
||||
provider:
|
||||
name: Eclipse Foundation
|
||||
version: 7.43.0-408.next
|
||||
version: 7.43.0-412.next
|
||||
|
|
|
|||
|
|
@ -61,14 +61,16 @@ spec:
|
|||
used by the Che installation.
|
||||
properties:
|
||||
debug:
|
||||
description: Debug internal identity provider.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Debug internal identity provider.
|
||||
type: boolean
|
||||
externalIdentityProvider:
|
||||
description: 'Instructs the Operator on whether or not to deploy
|
||||
a dedicated Identity Provider (Keycloak or RH SSO instance).
|
||||
Instructs the Operator on whether to deploy a dedicated Identity
|
||||
Provider (Keycloak or RH-SSO instance). By default, a dedicated
|
||||
Identity Provider server is deployed as part of the Che installation.
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Instructs the Operator on whether or not to deploy a dedicated
|
||||
Identity Provider (Keycloak or RH SSO instance). Instructs
|
||||
the Operator on whether to deploy a dedicated Identity Provider
|
||||
(Keycloak or RH-SSO instance). By default, a dedicated Identity
|
||||
Provider server is deployed as part of the Che installation.
|
||||
When `externalIdentityProvider` is `true`, no dedicated identity
|
||||
provider will be deployed by the Operator and you will need
|
||||
to provide details about the external identity provider you
|
||||
|
|
@ -90,18 +92,21 @@ spec:
|
|||
Sidecar functionality is now implemented in Traefik plugin.
|
||||
type: string
|
||||
identityProviderAdminUserName:
|
||||
description: Overrides the name of the Identity Provider administrator
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the name of the Identity Provider administrator
|
||||
user. Defaults to `admin`.
|
||||
type: string
|
||||
identityProviderClientId:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO,
|
||||
`client-id` that is used for Che. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to the value
|
||||
of the `flavour` field suffixed with `-public`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Name of a Identity provider, Keycloak or RH-SSO, `client-id`
|
||||
that is used for Che. Override this when an external Identity
|
||||
Provider is in use. See the `externalIdentityProvider` field.
|
||||
When omitted or left blank, it is set to the value of the
|
||||
`flavour` field suffixed with `-public`.
|
||||
type: string
|
||||
identityProviderContainerResources:
|
||||
description: Identity provider container custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Identity provider container custom settings.
|
||||
properties:
|
||||
limits:
|
||||
description: Limits describes the maximum amount of compute
|
||||
|
|
@ -129,19 +134,22 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
identityProviderImage:
|
||||
description: Overrides the container image used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. This includes the
|
||||
image tag. Omit it or leave it empty to use the default container
|
||||
image provided by the Operator.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the container image used in the Identity Provider,
|
||||
Keycloak or RH-SSO, deployment. This includes the image tag.
|
||||
Omit it or leave it empty to use the default container image
|
||||
provided by the Operator.
|
||||
type: string
|
||||
identityProviderImagePullPolicy:
|
||||
description: Overrides the image pull policy used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. Default value is
|
||||
`Always` for `nightly`, `next` or `latest` images, and `IfNotPresent`
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the image pull policy used in the Identity Provider,
|
||||
Keycloak or RH-SSO, deployment. Default value is `Always`
|
||||
for `nightly`, `next` or `latest` images, and `IfNotPresent`
|
||||
in other cases.
|
||||
type: string
|
||||
identityProviderIngress:
|
||||
description: Ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -157,25 +165,27 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderPassword:
|
||||
description: Overrides the password of Keycloak administrator
|
||||
user. Override this when an external Identity Provider is
|
||||
in use. See the `externalIdentityProvider` field. When omitted
|
||||
or left blank, it is set to an auto-generated password.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the password of Keycloak administrator user. Override
|
||||
this when an external Identity Provider is in use. See the
|
||||
`externalIdentityProvider` field. When omitted or left blank,
|
||||
it is set to an auto-generated password.
|
||||
type: string
|
||||
identityProviderPostgresPassword:
|
||||
description: Password for a Identity Provider, Keycloak or RH-SSO,
|
||||
to connect to the database. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to an auto-generated
|
||||
password.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Password for a Identity Provider, Keycloak or RH-SSO, to connect
|
||||
to the database. Override this when an external Identity Provider
|
||||
is in use. See the `externalIdentityProvider` field. When
|
||||
omitted or left blank, it is set to an auto-generated password.
|
||||
type: string
|
||||
identityProviderPostgresSecret:
|
||||
description: 'The secret that contains `password` for the Identity
|
||||
Provider, Keycloak or RH-SSO, to connect to the database.
|
||||
When the secret is defined, the `identityProviderPostgresPassword`
|
||||
is ignored. When the value is omitted or left blank, the one
|
||||
of following scenarios applies: 1. `identityProviderPostgresPassword`
|
||||
is defined, then it will be used to connect to the database.
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
The secret that contains `password` for the Identity Provider,
|
||||
Keycloak or RH-SSO, to connect to the database. When the secret
|
||||
is defined, the `identityProviderPostgresPassword` is ignored.
|
||||
When the value is omitted or left blank, the one of following
|
||||
scenarios applies: 1. `identityProviderPostgresPassword` is
|
||||
defined, then it will be used to connect to the database.
|
||||
2. `identityProviderPostgresPassword` is not defined, then
|
||||
a new secret with the name `che-identity-postgres-secret`
|
||||
will be created with an auto-generated value for `password`.
|
||||
|
|
@ -183,14 +193,16 @@ spec:
|
|||
label.'
|
||||
type: string
|
||||
identityProviderRealm:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO,
|
||||
realm that is used for Che. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to the value
|
||||
of the `flavour` field.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Name of a Identity provider, Keycloak or RH-SSO, realm that
|
||||
is used for Che. Override this when an external Identity Provider
|
||||
is in use. See the `externalIdentityProvider` field. When
|
||||
omitted or left blank, it is set to the value of the `flavour`
|
||||
field.
|
||||
type: string
|
||||
identityProviderRoute:
|
||||
description: Route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -212,8 +224,9 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderSecret:
|
||||
description: 'The secret that contains `user` and `password`
|
||||
for Identity Provider. When the secret is defined, the `identityProviderAdminUserName`
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
The secret that contains `user` and `password` for Identity
|
||||
Provider. When the secret is defined, the `identityProviderAdminUserName`
|
||||
and `identityProviderPassword` are ignored. When the value
|
||||
is omitted or left blank, the one of following scenarios applies:
|
||||
1. `identityProviderAdminUserName` and `identityProviderPassword`
|
||||
|
|
@ -232,20 +245,22 @@ spec:
|
|||
set by the Operator.
|
||||
type: string
|
||||
initialOpenShiftOAuthUser:
|
||||
description: For operating with the OpenShift OAuth authentication,
|
||||
create a new user account since the kubeadmin can not be used.
|
||||
If the value is true, then a new OpenShift OAuth user will
|
||||
be created for the HTPasswd identity provider. If the value
|
||||
is false and the user has already been created, then it will
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
For operating with the OpenShift OAuth authentication, create
|
||||
a new user account since the kubeadmin can not be used. If
|
||||
the value is true, then a new OpenShift OAuth user will be
|
||||
created for the HTPasswd identity provider. If the value is
|
||||
false and the user has already been created, then it will
|
||||
be removed. If value is an empty, then do nothing. The user's
|
||||
credentials are stored in the `openshift-oauth-user-credentials`
|
||||
secret in 'openshift-config' namespace by Operator. Note that
|
||||
this solution is Openshift 4 platform-specific.
|
||||
type: boolean
|
||||
nativeUserMode:
|
||||
description: Enables native user mode. Currently works only
|
||||
on OpenShift and DevWorkspace engine. Native User mode uses
|
||||
OpenShift OAuth directly as identity provider, without Keycloak.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Enables native user mode. Currently works only on OpenShift
|
||||
and DevWorkspace engine. Native User mode uses OpenShift OAuth
|
||||
directly as identity provider, without Keycloak.
|
||||
type: boolean
|
||||
oAuthClientName:
|
||||
description: Name of the OpenShift `OAuthClient` resource used
|
||||
|
|
@ -259,17 +274,19 @@ spec:
|
|||
field.
|
||||
type: string
|
||||
openShiftoAuth:
|
||||
description: 'Enables the integration of the identity provider
|
||||
(Keycloak / RHSSO) with OpenShift OAuth. Empty value on OpenShift
|
||||
by default. This will allow users to directly login with their
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Enables the integration of the identity provider (Keycloak
|
||||
/ RHSSO) with OpenShift OAuth. Empty value on OpenShift by
|
||||
default. This will allow users to directly login with their
|
||||
OpenShift user through the OpenShift login, and have their
|
||||
workspaces created under personal OpenShift namespaces. WARNING:
|
||||
the `kubeadmin` user is NOT supported, and logging through
|
||||
it will NOT allow accessing the Che Dashboard.'
|
||||
type: boolean
|
||||
updateAdminPassword:
|
||||
description: Forces the default `admin` Che user to update password
|
||||
on first login. Defaults to `false`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Forces the default `admin` Che user to update password on
|
||||
first login. Defaults to `false`.
|
||||
type: boolean
|
||||
type: object
|
||||
database:
|
||||
|
|
@ -456,10 +473,11 @@ spec:
|
|||
This MUST be explicitly specified: there are no defaults.'
|
||||
type: string
|
||||
ingressStrategy:
|
||||
description: 'Strategy for ingress creation. Options are: `multi-host`
|
||||
(host is explicitly provided in ingress), `single-host` (host
|
||||
is provided, path-based rules) and `default-host` (no host
|
||||
is provided, path-based rules). Defaults to `multi-host` Deprecated
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Strategy for ingress creation. Options are: `multi-host` (host
|
||||
is explicitly provided in ingress), `single-host` (host is
|
||||
provided, path-based rules) and `default-host` (no host is
|
||||
provided, path-based rules). Defaults to `multi-host` Deprecated
|
||||
in favor of `serverExposureStrategy` in the `server` section,
|
||||
which defines this regardless of the cluster type. When both
|
||||
are defined, the `serverExposureStrategy` option takes precedence.'
|
||||
|
|
@ -473,15 +491,16 @@ spec:
|
|||
run as. Default value is `1724`.
|
||||
type: string
|
||||
singleHostExposureType:
|
||||
description: When the serverExposureStrategy is set to `single-host`,
|
||||
the way the server, registries and workspaces are exposed
|
||||
is further configured by this property. The possible values
|
||||
are `native`, which means that the server and workspaces are
|
||||
exposed using ingresses on K8s or `gateway` where the server
|
||||
and workspaces are exposed using a custom gateway based on
|
||||
link:https://doc.traefik.io/traefik/[Traefik]. All the endpoints
|
||||
whether backed by the ingress or gateway `route` always point
|
||||
to the subpaths on the same domain. Defaults to `native`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
When the serverExposureStrategy is set to `single-host`, the
|
||||
way the server, registries and workspaces are exposed is further
|
||||
configured by this property. The possible values are `native`,
|
||||
which means that the server and workspaces are exposed using
|
||||
ingresses on K8s or `gateway` where the server and workspaces
|
||||
are exposed using a custom gateway based on link:https://doc.traefik.io/traefik/[Traefik].
|
||||
All the endpoints whether backed by the ingress or gateway
|
||||
`route` always point to the subpaths on the same domain. Defaults
|
||||
to `native`.
|
||||
type: string
|
||||
tlsSecretName:
|
||||
description: Name of a secret that will be used to setup ingress
|
||||
|
|
@ -535,9 +554,9 @@ spec:
|
|||
to `false`.
|
||||
type: string
|
||||
cheFlavor:
|
||||
description: Specifies a variation of the installation. The
|
||||
options are `che` for upstream Che installations, or `codeready`
|
||||
for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Specifies a variation of the installation. The options are
|
||||
`che` for upstream Che installations, or `codeready` for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
Workspaces] installation. Override the default value only
|
||||
on necessary occasions.
|
||||
type: string
|
||||
|
|
@ -646,7 +665,8 @@ spec:
|
|||
or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
dashboardIngress:
|
||||
description: Dashboard ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Dashboard ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -670,7 +690,8 @@ spec:
|
|||
deployment. Defaults to 16Mi.
|
||||
type: string
|
||||
dashboardRoute:
|
||||
description: Dashboard route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Dashboard route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -706,7 +727,8 @@ spec:
|
|||
by the Operator.
|
||||
type: string
|
||||
devfileRegistryIngress:
|
||||
description: The devfile registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
The devfile registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -735,7 +757,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
devfileRegistryRoute:
|
||||
description: The devfile registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
The devfile registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -761,9 +784,9 @@ spec:
|
|||
fields.
|
||||
type: string
|
||||
disableInternalClusterSVCNames:
|
||||
description: Disable internal cluster SVC names usage to communicate
|
||||
between components to speed up the traffic and avoid proxy
|
||||
issues.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Disable internal cluster SVC names usage to communicate between
|
||||
components to speed up the traffic and avoid proxy issues.
|
||||
type: boolean
|
||||
externalDevfileRegistries:
|
||||
description: External devfile registries, that serves sample,
|
||||
|
|
@ -828,7 +851,8 @@ spec:
|
|||
by the Operator.
|
||||
type: string
|
||||
pluginRegistryIngress:
|
||||
description: Plugin registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Plugin registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -857,7 +881,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
pluginRegistryRoute:
|
||||
description: Plugin registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Plugin registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -933,8 +958,9 @@ spec:
|
|||
deployment In cores. (500m = .5 cores). Default to 100m.
|
||||
type: string
|
||||
serverExposureStrategy:
|
||||
description: Sets the server and workspaces exposure type. Possible
|
||||
values are `multi-host`, `single-host`, `default-host`. Defaults
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Sets the server and workspaces exposure type. Possible values
|
||||
are `multi-host`, `single-host`, `default-host`. Defaults
|
||||
to `multi-host`, which creates a separate ingress, or OpenShift
|
||||
routes, for every required endpoint. `single-host` makes Che
|
||||
exposed on a single host name with workspaces exposed on subpaths.
|
||||
|
|
|
|||
|
|
@ -54,18 +54,20 @@ spec:
|
|||
by the Che installation.
|
||||
properties:
|
||||
debug:
|
||||
description: Debug internal identity provider.
|
||||
description: Deprecated. The value of this flag is ignored. Debug
|
||||
internal identity provider.
|
||||
type: boolean
|
||||
externalIdentityProvider:
|
||||
description: 'Instructs the Operator on whether or not to deploy
|
||||
a dedicated Identity Provider (Keycloak or RH SSO instance). Instructs
|
||||
the Operator on whether to deploy a dedicated Identity Provider
|
||||
(Keycloak or RH-SSO instance). By default, a dedicated Identity
|
||||
Provider server is deployed as part of the Che installation. When
|
||||
`externalIdentityProvider` is `true`, no dedicated identity provider
|
||||
will be deployed by the Operator and you will need to provide
|
||||
details about the external identity provider you are about to
|
||||
use. See also all the other fields starting with: `identityProvider`.'
|
||||
description: 'Deprecated. The value of this flag is ignored. Instructs
|
||||
the Operator on whether or not to deploy a dedicated Identity
|
||||
Provider (Keycloak or RH SSO instance). Instructs the Operator
|
||||
on whether to deploy a dedicated Identity Provider (Keycloak or
|
||||
RH-SSO instance). By default, a dedicated Identity Provider server
|
||||
is deployed as part of the Che installation. When `externalIdentityProvider`
|
||||
is `true`, no dedicated identity provider will be deployed by
|
||||
the Operator and you will need to provide details about the external
|
||||
identity provider you are about to use. See also all the other
|
||||
fields starting with: `identityProvider`.'
|
||||
type: boolean
|
||||
gatewayAuthenticationSidecarImage:
|
||||
description: Gateway sidecar responsible for authentication when
|
||||
|
|
@ -82,18 +84,21 @@ spec:
|
|||
functionality is now implemented in Traefik plugin.
|
||||
type: string
|
||||
identityProviderAdminUserName:
|
||||
description: Overrides the name of the Identity Provider administrator
|
||||
user. Defaults to `admin`.
|
||||
description: Deprecated. The value of this flag is ignored. Overrides
|
||||
the name of the Identity Provider administrator user. Defaults
|
||||
to `admin`.
|
||||
type: string
|
||||
identityProviderClientId:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO, `client-id`
|
||||
that is used for Che. Override this when an external Identity
|
||||
Provider is in use. See the `externalIdentityProvider` field.
|
||||
When omitted or left blank, it is set to the value of the `flavour`
|
||||
field suffixed with `-public`.
|
||||
description: Deprecated. The value of this flag is ignored. Name
|
||||
of a Identity provider, Keycloak or RH-SSO, `client-id` that is
|
||||
used for Che. Override this when an external Identity Provider
|
||||
is in use. See the `externalIdentityProvider` field. When omitted
|
||||
or left blank, it is set to the value of the `flavour` field suffixed
|
||||
with `-public`.
|
||||
type: string
|
||||
identityProviderContainerResources:
|
||||
description: Identity provider container custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. Identity
|
||||
provider container custom settings.
|
||||
properties:
|
||||
limits:
|
||||
description: Limits describes the maximum amount of compute
|
||||
|
|
@ -121,19 +126,20 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
identityProviderImage:
|
||||
description: Overrides the container image used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. This includes the image
|
||||
tag. Omit it or leave it empty to use the default container image
|
||||
provided by the Operator.
|
||||
description: Deprecated. The value of this flag is ignored. Overrides
|
||||
the container image used in the Identity Provider, Keycloak or
|
||||
RH-SSO, deployment. This includes the image tag. Omit it or leave
|
||||
it empty to use the default container image provided by the Operator.
|
||||
type: string
|
||||
identityProviderImagePullPolicy:
|
||||
description: Overrides the image pull policy used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. Default value is `Always`
|
||||
for `nightly`, `next` or `latest` images, and `IfNotPresent` in
|
||||
other cases.
|
||||
description: Deprecated. The value of this flag is ignored. Overrides
|
||||
the image pull policy used in the Identity Provider, Keycloak
|
||||
or RH-SSO, deployment. Default value is `Always` for `nightly`,
|
||||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
identityProviderIngress:
|
||||
description: Ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. Ingress
|
||||
custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -148,38 +154,41 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderPassword:
|
||||
description: Overrides the password of Keycloak administrator user.
|
||||
Override this when an external Identity Provider is in use. See
|
||||
the `externalIdentityProvider` field. When omitted or left blank,
|
||||
it is set to an auto-generated password.
|
||||
description: Deprecated. The value of this flag is ignored. Overrides
|
||||
the password of Keycloak administrator user. Override this when
|
||||
an external Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to an auto-generated
|
||||
password.
|
||||
type: string
|
||||
identityProviderPostgresPassword:
|
||||
description: Password for a Identity Provider, Keycloak or RH-SSO,
|
||||
to connect to the database. Override this when an external Identity
|
||||
Provider is in use. See the `externalIdentityProvider` field.
|
||||
When omitted or left blank, it is set to an auto-generated password.
|
||||
description: Deprecated. The value of this flag is ignored. Password
|
||||
for a Identity Provider, Keycloak or RH-SSO, to connect to the
|
||||
database. Override this when an external Identity Provider is
|
||||
in use. See the `externalIdentityProvider` field. When omitted
|
||||
or left blank, it is set to an auto-generated password.
|
||||
type: string
|
||||
identityProviderPostgresSecret:
|
||||
description: 'The secret that contains `password` for the Identity
|
||||
Provider, Keycloak or RH-SSO, to connect to the database. When
|
||||
the secret is defined, the `identityProviderPostgresPassword`
|
||||
is ignored. When the value is omitted or left blank, the one of
|
||||
following scenarios applies: 1. `identityProviderPostgresPassword`
|
||||
is defined, then it will be used to connect to the database. 2.
|
||||
`identityProviderPostgresPassword` is not defined, then a new
|
||||
secret with the name `che-identity-postgres-secret` will be created
|
||||
with an auto-generated value for `password`. The secret must have
|
||||
`app.kubernetes.io/part-of=che.eclipse.org` label.'
|
||||
description: 'Deprecated. The value of this flag is ignored. The
|
||||
secret that contains `password` for the Identity Provider, Keycloak
|
||||
or RH-SSO, to connect to the database. When the secret is defined,
|
||||
the `identityProviderPostgresPassword` is ignored. When the value
|
||||
is omitted or left blank, the one of following scenarios applies:
|
||||
1. `identityProviderPostgresPassword` is defined, then it will
|
||||
be used to connect to the database. 2. `identityProviderPostgresPassword`
|
||||
is not defined, then a new secret with the name `che-identity-postgres-secret`
|
||||
will be created with an auto-generated value for `password`. The
|
||||
secret must have `app.kubernetes.io/part-of=che.eclipse.org` label.'
|
||||
type: string
|
||||
identityProviderRealm:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO, realm
|
||||
that is used for Che. Override this when an external Identity
|
||||
Provider is in use. See the `externalIdentityProvider` field.
|
||||
When omitted or left blank, it is set to the value of the `flavour`
|
||||
field.
|
||||
description: Deprecated. The value of this flag is ignored. Name
|
||||
of a Identity provider, Keycloak or RH-SSO, realm that is used
|
||||
for Che. Override this when an external Identity Provider is in
|
||||
use. See the `externalIdentityProvider` field. When omitted or
|
||||
left blank, it is set to the value of the `flavour` field.
|
||||
type: string
|
||||
identityProviderRoute:
|
||||
description: Route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. Route
|
||||
custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -200,8 +209,9 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderSecret:
|
||||
description: 'The secret that contains `user` and `password` for
|
||||
Identity Provider. When the secret is defined, the `identityProviderAdminUserName`
|
||||
description: 'Deprecated. The value of this flag is ignored. The
|
||||
secret that contains `user` and `password` for Identity Provider.
|
||||
When the secret is defined, the `identityProviderAdminUserName`
|
||||
and `identityProviderPassword` are ignored. When the value is
|
||||
omitted or left blank, the one of following scenarios applies:
|
||||
1. `identityProviderAdminUserName` and `identityProviderPassword`
|
||||
|
|
@ -220,20 +230,22 @@ spec:
|
|||
Operator.
|
||||
type: string
|
||||
initialOpenShiftOAuthUser:
|
||||
description: For operating with the OpenShift OAuth authentication,
|
||||
create a new user account since the kubeadmin can not be used.
|
||||
If the value is true, then a new OpenShift OAuth user will be
|
||||
created for the HTPasswd identity provider. If the value is false
|
||||
and the user has already been created, then it will be removed.
|
||||
If value is an empty, then do nothing. The user's credentials
|
||||
are stored in the `openshift-oauth-user-credentials` secret in
|
||||
'openshift-config' namespace by Operator. Note that this solution
|
||||
is Openshift 4 platform-specific.
|
||||
description: Deprecated. The value of this flag is ignored. For
|
||||
operating with the OpenShift OAuth authentication, create a new
|
||||
user account since the kubeadmin can not be used. If the value
|
||||
is true, then a new OpenShift OAuth user will be created for the
|
||||
HTPasswd identity provider. If the value is false and the user
|
||||
has already been created, then it will be removed. If value is
|
||||
an empty, then do nothing. The user's credentials are stored in
|
||||
the `openshift-oauth-user-credentials` secret in 'openshift-config'
|
||||
namespace by Operator. Note that this solution is Openshift 4
|
||||
platform-specific.
|
||||
type: boolean
|
||||
nativeUserMode:
|
||||
description: Enables native user mode. Currently works only on OpenShift
|
||||
and DevWorkspace engine. Native User mode uses OpenShift OAuth
|
||||
directly as identity provider, without Keycloak.
|
||||
description: Deprecated. The value of this flag is ignored. Enables
|
||||
native user mode. Currently works only on OpenShift and DevWorkspace
|
||||
engine. Native User mode uses OpenShift OAuth directly as identity
|
||||
provider, without Keycloak.
|
||||
type: boolean
|
||||
oAuthClientName:
|
||||
description: Name of the OpenShift `OAuthClient` resource used to
|
||||
|
|
@ -247,17 +259,18 @@ spec:
|
|||
field.
|
||||
type: string
|
||||
openShiftoAuth:
|
||||
description: 'Enables the integration of the identity provider (Keycloak
|
||||
/ RHSSO) with OpenShift OAuth. Empty value on OpenShift by default.
|
||||
This will allow users to directly login with their OpenShift user
|
||||
through the OpenShift login, and have their workspaces created
|
||||
under personal OpenShift namespaces. WARNING: the `kubeadmin`
|
||||
user is NOT supported, and logging through it will NOT allow accessing
|
||||
the Che Dashboard.'
|
||||
description: 'Deprecated. The value of this flag is ignored. Enables
|
||||
the integration of the identity provider (Keycloak / RHSSO) with
|
||||
OpenShift OAuth. Empty value on OpenShift by default. This will
|
||||
allow users to directly login with their OpenShift user through
|
||||
the OpenShift login, and have their workspaces created under personal
|
||||
OpenShift namespaces. WARNING: the `kubeadmin` user is NOT supported,
|
||||
and logging through it will NOT allow accessing the Che Dashboard.'
|
||||
type: boolean
|
||||
updateAdminPassword:
|
||||
description: Forces the default `admin` Che user to update password
|
||||
on first login. Defaults to `false`.
|
||||
description: Deprecated. The value of this flag is ignored. Forces
|
||||
the default `admin` Che user to update password on first login.
|
||||
Defaults to `false`.
|
||||
type: boolean
|
||||
type: object
|
||||
database:
|
||||
|
|
@ -436,13 +449,14 @@ spec:
|
|||
MUST be explicitly specified: there are no defaults.'
|
||||
type: string
|
||||
ingressStrategy:
|
||||
description: 'Strategy for ingress creation. Options are: `multi-host`
|
||||
(host is explicitly provided in ingress), `single-host` (host
|
||||
is provided, path-based rules) and `default-host` (no host is
|
||||
provided, path-based rules). Defaults to `multi-host` Deprecated
|
||||
in favor of `serverExposureStrategy` in the `server` section,
|
||||
which defines this regardless of the cluster type. When both are
|
||||
defined, the `serverExposureStrategy` option takes precedence.'
|
||||
description: 'Deprecated. The value of this flag is ignored. Strategy
|
||||
for ingress creation. Options are: `multi-host` (host is explicitly
|
||||
provided in ingress), `single-host` (host is provided, path-based
|
||||
rules) and `default-host` (no host is provided, path-based rules).
|
||||
Defaults to `multi-host` Deprecated in favor of `serverExposureStrategy`
|
||||
in the `server` section, which defines this regardless of the
|
||||
cluster type. When both are defined, the `serverExposureStrategy`
|
||||
option takes precedence.'
|
||||
type: string
|
||||
securityContextFsGroup:
|
||||
description: The FSGroup in which the Che Pod and workspace Pods
|
||||
|
|
@ -453,12 +467,13 @@ spec:
|
|||
run as. Default value is `1724`.
|
||||
type: string
|
||||
singleHostExposureType:
|
||||
description: When the serverExposureStrategy is set to `single-host`,
|
||||
the way the server, registries and workspaces are exposed is further
|
||||
configured by this property. The possible values are `native`,
|
||||
which means that the server and workspaces are exposed using ingresses
|
||||
on K8s or `gateway` where the server and workspaces are exposed
|
||||
using a custom gateway based on link:https://doc.traefik.io/traefik/[Traefik].
|
||||
description: Deprecated. The value of this flag is ignored. When
|
||||
the serverExposureStrategy is set to `single-host`, the way the
|
||||
server, registries and workspaces are exposed is further configured
|
||||
by this property. The possible values are `native`, which means
|
||||
that the server and workspaces are exposed using ingresses on
|
||||
K8s or `gateway` where the server and workspaces are exposed using
|
||||
a custom gateway based on link:https://doc.traefik.io/traefik/[Traefik].
|
||||
All the endpoints whether backed by the ingress or gateway `route`
|
||||
always point to the subpaths on the same domain. Defaults to `native`.
|
||||
type: string
|
||||
|
|
@ -514,8 +529,9 @@ spec:
|
|||
`false`.
|
||||
type: string
|
||||
cheFlavor:
|
||||
description: Specifies a variation of the installation. The options
|
||||
are `che` for upstream Che installations, or `codeready` for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
description: Deprecated. The value of this flag is ignored. Specifies
|
||||
a variation of the installation. The options are `che` for upstream
|
||||
Che installations, or `codeready` for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
Workspaces] installation. Override the default value only on necessary
|
||||
occasions.
|
||||
type: string
|
||||
|
|
@ -620,7 +636,8 @@ spec:
|
|||
`latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
dashboardIngress:
|
||||
description: Dashboard ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. Dashboard
|
||||
ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -643,7 +660,8 @@ spec:
|
|||
deployment. Defaults to 16Mi.
|
||||
type: string
|
||||
dashboardRoute:
|
||||
description: Dashboard route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. Dashboard
|
||||
route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -677,7 +695,8 @@ spec:
|
|||
to use the default container image provided by the Operator.
|
||||
type: string
|
||||
devfileRegistryIngress:
|
||||
description: The devfile registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. The
|
||||
devfile registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -705,7 +724,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
devfileRegistryRoute:
|
||||
description: The devfile registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. The
|
||||
devfile registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -730,8 +750,9 @@ spec:
|
|||
fields.
|
||||
type: string
|
||||
disableInternalClusterSVCNames:
|
||||
description: Disable internal cluster SVC names usage to communicate
|
||||
between components to speed up the traffic and avoid proxy issues.
|
||||
description: Deprecated. The value of this flag is ignored. Disable
|
||||
internal cluster SVC names usage to communicate between components
|
||||
to speed up the traffic and avoid proxy issues.
|
||||
type: boolean
|
||||
externalDevfileRegistries:
|
||||
description: External devfile registries, that serves sample, ready-to-use
|
||||
|
|
@ -795,7 +816,8 @@ spec:
|
|||
to use the default container image provided by the Operator.
|
||||
type: string
|
||||
pluginRegistryIngress:
|
||||
description: Plugin registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. Plugin
|
||||
registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -823,7 +845,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
pluginRegistryRoute:
|
||||
description: Plugin registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored. Plugin
|
||||
registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -897,16 +920,17 @@ spec:
|
|||
In cores. (500m = .5 cores). Default to 100m.
|
||||
type: string
|
||||
serverExposureStrategy:
|
||||
description: Sets the server and workspaces exposure type. Possible
|
||||
values are `multi-host`, `single-host`, `default-host`. Defaults
|
||||
to `multi-host`, which creates a separate ingress, or OpenShift
|
||||
routes, for every required endpoint. `single-host` makes Che exposed
|
||||
on a single host name with workspaces exposed on subpaths. Read
|
||||
the docs to learn about the limitations of this approach. Also
|
||||
consult the `singleHostExposureType` property to further configure
|
||||
how the Operator and the Che server make that happen on Kubernetes.
|
||||
`default-host` exposes the Che server on the host of the cluster.
|
||||
Read the docs to learn about the limitations of this approach.
|
||||
description: Deprecated. The value of this flag is ignored. Sets
|
||||
the server and workspaces exposure type. Possible values are `multi-host`,
|
||||
`single-host`, `default-host`. Defaults to `multi-host`, which
|
||||
creates a separate ingress, or OpenShift routes, for every required
|
||||
endpoint. `single-host` makes Che exposed on a single host name
|
||||
with workspaces exposed on subpaths. Read the docs to learn about
|
||||
the limitations of this approach. Also consult the `singleHostExposureType`
|
||||
property to further configure how the Operator and the Che server
|
||||
make that happen on Kubernetes. `default-host` exposes the Che
|
||||
server on the host of the cluster. Read the docs to learn about
|
||||
the limitations of this approach.
|
||||
type: string
|
||||
serverMemoryLimit:
|
||||
description: Overrides the memory limit used in the Che server deployment.
|
||||
|
|
|
|||
|
|
@ -57,14 +57,16 @@ spec:
|
|||
used by the Che installation.
|
||||
properties:
|
||||
debug:
|
||||
description: Debug internal identity provider.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Debug internal identity provider.
|
||||
type: boolean
|
||||
externalIdentityProvider:
|
||||
description: 'Instructs the Operator on whether or not to deploy
|
||||
a dedicated Identity Provider (Keycloak or RH SSO instance).
|
||||
Instructs the Operator on whether to deploy a dedicated Identity
|
||||
Provider (Keycloak or RH-SSO instance). By default, a dedicated
|
||||
Identity Provider server is deployed as part of the Che installation.
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Instructs the Operator on whether or not to deploy a dedicated
|
||||
Identity Provider (Keycloak or RH SSO instance). Instructs
|
||||
the Operator on whether to deploy a dedicated Identity Provider
|
||||
(Keycloak or RH-SSO instance). By default, a dedicated Identity
|
||||
Provider server is deployed as part of the Che installation.
|
||||
When `externalIdentityProvider` is `true`, no dedicated identity
|
||||
provider will be deployed by the Operator and you will need
|
||||
to provide details about the external identity provider you
|
||||
|
|
@ -86,18 +88,21 @@ spec:
|
|||
Sidecar functionality is now implemented in Traefik plugin.
|
||||
type: string
|
||||
identityProviderAdminUserName:
|
||||
description: Overrides the name of the Identity Provider administrator
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the name of the Identity Provider administrator
|
||||
user. Defaults to `admin`.
|
||||
type: string
|
||||
identityProviderClientId:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO,
|
||||
`client-id` that is used for Che. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to the value
|
||||
of the `flavour` field suffixed with `-public`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Name of a Identity provider, Keycloak or RH-SSO, `client-id`
|
||||
that is used for Che. Override this when an external Identity
|
||||
Provider is in use. See the `externalIdentityProvider` field.
|
||||
When omitted or left blank, it is set to the value of the
|
||||
`flavour` field suffixed with `-public`.
|
||||
type: string
|
||||
identityProviderContainerResources:
|
||||
description: Identity provider container custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Identity provider container custom settings.
|
||||
properties:
|
||||
limits:
|
||||
description: Limits describes the maximum amount of compute
|
||||
|
|
@ -125,19 +130,22 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
identityProviderImage:
|
||||
description: Overrides the container image used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. This includes the
|
||||
image tag. Omit it or leave it empty to use the default container
|
||||
image provided by the Operator.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the container image used in the Identity Provider,
|
||||
Keycloak or RH-SSO, deployment. This includes the image tag.
|
||||
Omit it or leave it empty to use the default container image
|
||||
provided by the Operator.
|
||||
type: string
|
||||
identityProviderImagePullPolicy:
|
||||
description: Overrides the image pull policy used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. Default value is
|
||||
`Always` for `nightly`, `next` or `latest` images, and `IfNotPresent`
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the image pull policy used in the Identity Provider,
|
||||
Keycloak or RH-SSO, deployment. Default value is `Always`
|
||||
for `nightly`, `next` or `latest` images, and `IfNotPresent`
|
||||
in other cases.
|
||||
type: string
|
||||
identityProviderIngress:
|
||||
description: Ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -153,25 +161,27 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderPassword:
|
||||
description: Overrides the password of Keycloak administrator
|
||||
user. Override this when an external Identity Provider is
|
||||
in use. See the `externalIdentityProvider` field. When omitted
|
||||
or left blank, it is set to an auto-generated password.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the password of Keycloak administrator user. Override
|
||||
this when an external Identity Provider is in use. See the
|
||||
`externalIdentityProvider` field. When omitted or left blank,
|
||||
it is set to an auto-generated password.
|
||||
type: string
|
||||
identityProviderPostgresPassword:
|
||||
description: Password for a Identity Provider, Keycloak or RH-SSO,
|
||||
to connect to the database. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to an auto-generated
|
||||
password.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Password for a Identity Provider, Keycloak or RH-SSO, to connect
|
||||
to the database. Override this when an external Identity Provider
|
||||
is in use. See the `externalIdentityProvider` field. When
|
||||
omitted or left blank, it is set to an auto-generated password.
|
||||
type: string
|
||||
identityProviderPostgresSecret:
|
||||
description: 'The secret that contains `password` for the Identity
|
||||
Provider, Keycloak or RH-SSO, to connect to the database.
|
||||
When the secret is defined, the `identityProviderPostgresPassword`
|
||||
is ignored. When the value is omitted or left blank, the one
|
||||
of following scenarios applies: 1. `identityProviderPostgresPassword`
|
||||
is defined, then it will be used to connect to the database.
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
The secret that contains `password` for the Identity Provider,
|
||||
Keycloak or RH-SSO, to connect to the database. When the secret
|
||||
is defined, the `identityProviderPostgresPassword` is ignored.
|
||||
When the value is omitted or left blank, the one of following
|
||||
scenarios applies: 1. `identityProviderPostgresPassword` is
|
||||
defined, then it will be used to connect to the database.
|
||||
2. `identityProviderPostgresPassword` is not defined, then
|
||||
a new secret with the name `che-identity-postgres-secret`
|
||||
will be created with an auto-generated value for `password`.
|
||||
|
|
@ -179,14 +189,16 @@ spec:
|
|||
label.'
|
||||
type: string
|
||||
identityProviderRealm:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO,
|
||||
realm that is used for Che. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to the value
|
||||
of the `flavour` field.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Name of a Identity provider, Keycloak or RH-SSO, realm that
|
||||
is used for Che. Override this when an external Identity Provider
|
||||
is in use. See the `externalIdentityProvider` field. When
|
||||
omitted or left blank, it is set to the value of the `flavour`
|
||||
field.
|
||||
type: string
|
||||
identityProviderRoute:
|
||||
description: Route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -208,8 +220,9 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderSecret:
|
||||
description: 'The secret that contains `user` and `password`
|
||||
for Identity Provider. When the secret is defined, the `identityProviderAdminUserName`
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
The secret that contains `user` and `password` for Identity
|
||||
Provider. When the secret is defined, the `identityProviderAdminUserName`
|
||||
and `identityProviderPassword` are ignored. When the value
|
||||
is omitted or left blank, the one of following scenarios applies:
|
||||
1. `identityProviderAdminUserName` and `identityProviderPassword`
|
||||
|
|
@ -228,20 +241,22 @@ spec:
|
|||
set by the Operator.
|
||||
type: string
|
||||
initialOpenShiftOAuthUser:
|
||||
description: For operating with the OpenShift OAuth authentication,
|
||||
create a new user account since the kubeadmin can not be used.
|
||||
If the value is true, then a new OpenShift OAuth user will
|
||||
be created for the HTPasswd identity provider. If the value
|
||||
is false and the user has already been created, then it will
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
For operating with the OpenShift OAuth authentication, create
|
||||
a new user account since the kubeadmin can not be used. If
|
||||
the value is true, then a new OpenShift OAuth user will be
|
||||
created for the HTPasswd identity provider. If the value is
|
||||
false and the user has already been created, then it will
|
||||
be removed. If value is an empty, then do nothing. The user's
|
||||
credentials are stored in the `openshift-oauth-user-credentials`
|
||||
secret in 'openshift-config' namespace by Operator. Note that
|
||||
this solution is Openshift 4 platform-specific.
|
||||
type: boolean
|
||||
nativeUserMode:
|
||||
description: Enables native user mode. Currently works only
|
||||
on OpenShift and DevWorkspace engine. Native User mode uses
|
||||
OpenShift OAuth directly as identity provider, without Keycloak.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Enables native user mode. Currently works only on OpenShift
|
||||
and DevWorkspace engine. Native User mode uses OpenShift OAuth
|
||||
directly as identity provider, without Keycloak.
|
||||
type: boolean
|
||||
oAuthClientName:
|
||||
description: Name of the OpenShift `OAuthClient` resource used
|
||||
|
|
@ -255,17 +270,19 @@ spec:
|
|||
field.
|
||||
type: string
|
||||
openShiftoAuth:
|
||||
description: 'Enables the integration of the identity provider
|
||||
(Keycloak / RHSSO) with OpenShift OAuth. Empty value on OpenShift
|
||||
by default. This will allow users to directly login with their
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Enables the integration of the identity provider (Keycloak
|
||||
/ RHSSO) with OpenShift OAuth. Empty value on OpenShift by
|
||||
default. This will allow users to directly login with their
|
||||
OpenShift user through the OpenShift login, and have their
|
||||
workspaces created under personal OpenShift namespaces. WARNING:
|
||||
the `kubeadmin` user is NOT supported, and logging through
|
||||
it will NOT allow accessing the Che Dashboard.'
|
||||
type: boolean
|
||||
updateAdminPassword:
|
||||
description: Forces the default `admin` Che user to update password
|
||||
on first login. Defaults to `false`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Forces the default `admin` Che user to update password on
|
||||
first login. Defaults to `false`.
|
||||
type: boolean
|
||||
type: object
|
||||
database:
|
||||
|
|
@ -452,10 +469,11 @@ spec:
|
|||
This MUST be explicitly specified: there are no defaults.'
|
||||
type: string
|
||||
ingressStrategy:
|
||||
description: 'Strategy for ingress creation. Options are: `multi-host`
|
||||
(host is explicitly provided in ingress), `single-host` (host
|
||||
is provided, path-based rules) and `default-host` (no host
|
||||
is provided, path-based rules). Defaults to `multi-host` Deprecated
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Strategy for ingress creation. Options are: `multi-host` (host
|
||||
is explicitly provided in ingress), `single-host` (host is
|
||||
provided, path-based rules) and `default-host` (no host is
|
||||
provided, path-based rules). Defaults to `multi-host` Deprecated
|
||||
in favor of `serverExposureStrategy` in the `server` section,
|
||||
which defines this regardless of the cluster type. When both
|
||||
are defined, the `serverExposureStrategy` option takes precedence.'
|
||||
|
|
@ -469,15 +487,16 @@ spec:
|
|||
run as. Default value is `1724`.
|
||||
type: string
|
||||
singleHostExposureType:
|
||||
description: When the serverExposureStrategy is set to `single-host`,
|
||||
the way the server, registries and workspaces are exposed
|
||||
is further configured by this property. The possible values
|
||||
are `native`, which means that the server and workspaces are
|
||||
exposed using ingresses on K8s or `gateway` where the server
|
||||
and workspaces are exposed using a custom gateway based on
|
||||
link:https://doc.traefik.io/traefik/[Traefik]. All the endpoints
|
||||
whether backed by the ingress or gateway `route` always point
|
||||
to the subpaths on the same domain. Defaults to `native`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
When the serverExposureStrategy is set to `single-host`, the
|
||||
way the server, registries and workspaces are exposed is further
|
||||
configured by this property. The possible values are `native`,
|
||||
which means that the server and workspaces are exposed using
|
||||
ingresses on K8s or `gateway` where the server and workspaces
|
||||
are exposed using a custom gateway based on link:https://doc.traefik.io/traefik/[Traefik].
|
||||
All the endpoints whether backed by the ingress or gateway
|
||||
`route` always point to the subpaths on the same domain. Defaults
|
||||
to `native`.
|
||||
type: string
|
||||
tlsSecretName:
|
||||
description: Name of a secret that will be used to setup ingress
|
||||
|
|
@ -531,9 +550,9 @@ spec:
|
|||
to `false`.
|
||||
type: string
|
||||
cheFlavor:
|
||||
description: Specifies a variation of the installation. The
|
||||
options are `che` for upstream Che installations, or `codeready`
|
||||
for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Specifies a variation of the installation. The options are
|
||||
`che` for upstream Che installations, or `codeready` for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
Workspaces] installation. Override the default value only
|
||||
on necessary occasions.
|
||||
type: string
|
||||
|
|
@ -642,7 +661,8 @@ spec:
|
|||
or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
dashboardIngress:
|
||||
description: Dashboard ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Dashboard ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -666,7 +686,8 @@ spec:
|
|||
deployment. Defaults to 16Mi.
|
||||
type: string
|
||||
dashboardRoute:
|
||||
description: Dashboard route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Dashboard route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -702,7 +723,8 @@ spec:
|
|||
by the Operator.
|
||||
type: string
|
||||
devfileRegistryIngress:
|
||||
description: The devfile registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
The devfile registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -731,7 +753,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
devfileRegistryRoute:
|
||||
description: The devfile registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
The devfile registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -757,9 +780,9 @@ spec:
|
|||
fields.
|
||||
type: string
|
||||
disableInternalClusterSVCNames:
|
||||
description: Disable internal cluster SVC names usage to communicate
|
||||
between components to speed up the traffic and avoid proxy
|
||||
issues.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Disable internal cluster SVC names usage to communicate between
|
||||
components to speed up the traffic and avoid proxy issues.
|
||||
type: boolean
|
||||
externalDevfileRegistries:
|
||||
description: External devfile registries, that serves sample,
|
||||
|
|
@ -824,7 +847,8 @@ spec:
|
|||
by the Operator.
|
||||
type: string
|
||||
pluginRegistryIngress:
|
||||
description: Plugin registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Plugin registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -853,7 +877,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
pluginRegistryRoute:
|
||||
description: Plugin registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Plugin registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -929,8 +954,9 @@ spec:
|
|||
deployment In cores. (500m = .5 cores). Default to 100m.
|
||||
type: string
|
||||
serverExposureStrategy:
|
||||
description: Sets the server and workspaces exposure type. Possible
|
||||
values are `multi-host`, `single-host`, `default-host`. Defaults
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Sets the server and workspaces exposure type. Possible values
|
||||
are `multi-host`, `single-host`, `default-host`. Defaults
|
||||
to `multi-host`, which creates a separate ingress, or OpenShift
|
||||
routes, for every required endpoint. `single-host` makes Che
|
||||
exposed on a single host name with workspaces exposed on subpaths.
|
||||
|
|
|
|||
|
|
@ -77,8 +77,6 @@ spec:
|
|||
value: quay.io/eclipse/che--centos--postgresql-96-centos7:9.6-b681d78125361519180a6ac05242c296f8906c11eab7e207b5ca9a89b6344392
|
||||
- name: RELATED_IMAGE_postgres_13_3
|
||||
value: quay.io/eclipse/che--centos--postgresql-13-centos7:1-71b24684d64da46f960682cc4216222a7e4ed8b1a31dd5a865b3e71afdea20d2
|
||||
- name: RELATED_IMAGE_keycloak
|
||||
value: quay.io/eclipse/che-keycloak:next
|
||||
- name: RELATED_IMAGE_che_workspace_plugin_broker_metadata
|
||||
value: quay.io/eclipse/che-plugin-metadata-broker:v3.4.0
|
||||
- name: RELATED_IMAGE_che_workspace_plugin_broker_artifacts
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ spec:
|
|||
cheWorkspaceClusterRole: ''
|
||||
# When enabled, the certificate from `che-git-self-signed-cert` ConfigMap will be propagated to the Che components and provide particular configuration for Git.
|
||||
gitSelfSignedCert: false
|
||||
# Deprecated. Instructs the Operator to deploy Che in TLS mode. Disabling TLS sometimes cause malfunction of some Che components.
|
||||
tlsSupport: true
|
||||
# URL (protocol+host name) of the proxy server. This drives the appropriate changes in the `JAVA_OPTS` and `https(s)_proxy` variables
|
||||
# in the Che server and workspaces containers.
|
||||
# Only use when configuring a proxy is required. Operator respects OpenShift cluster wide proxy configuration
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import (
|
|||
identityprovider "github.com/eclipse-che/che-operator/pkg/deploy/identity-provider"
|
||||
imagepuller "github.com/eclipse-che/che-operator/pkg/deploy/image-puller"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/migration"
|
||||
openshiftoauth "github.com/eclipse-che/che-operator/pkg/deploy/openshift-oauth"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/pluginregistry"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/postgres"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/rbac"
|
||||
|
|
@ -93,9 +92,6 @@ func NewReconciler(
|
|||
}
|
||||
reconcileManager.RegisterReconciler(imagepuller.NewImagePuller())
|
||||
|
||||
openShiftOAuthUser := openshiftoauth.NewOpenShiftOAuthUser()
|
||||
reconcileManager.RegisterReconciler(openShiftOAuthUser)
|
||||
reconcileManager.RegisterReconciler(openshiftoauth.NewOpenShiftOAuth(openShiftOAuthUser))
|
||||
reconcileManager.RegisterReconciler(tls.NewCertificatesReconciler())
|
||||
reconcileManager.RegisterReconciler(tls.NewTlsSecretReconciler())
|
||||
reconcileManager.RegisterReconciler(devworkspace.NewDevWorkspaceReconciler())
|
||||
|
|
|
|||
|
|
@ -1,297 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 che
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"time"
|
||||
|
||||
chev1alpha1 "github.com/che-incubator/kubernetes-image-puller-operator/api/v1alpha1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
|
||||
console "github.com/openshift/api/console/v1"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
oauthv1 "github.com/openshift/api/oauth/v1"
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
userv1 "github.com/openshift/api/user/v1"
|
||||
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
|
||||
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
|
||||
packagesv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakeDiscovery "k8s.io/client-go/discovery/fake"
|
||||
fakeclientset "k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
|
||||
configv1 "github.com/openshift/api/config/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
namespace = "eclipse-che"
|
||||
)
|
||||
|
||||
func TestCheController(t *testing.T) {
|
||||
var err error
|
||||
|
||||
util.IsOpenShift = true
|
||||
util.IsOpenShift4 = true
|
||||
|
||||
cl, dc, scheme := Init()
|
||||
|
||||
// Create a ReconcileChe object with the scheme and fake client
|
||||
r := NewReconciler(cl, cl, dc, &scheme, "")
|
||||
|
||||
// get CR
|
||||
checluster := &orgv1.CheCluster{}
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: os.Getenv("CHE_FLAVOR"), Namespace: namespace}, checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Mock request to simulate Reconcile() being called on an event for a
|
||||
// watched resource .
|
||||
req := reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
Name: os.Getenv("CHE_FLAVOR"),
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = r.Reconcile(context.TODO(), req)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.True(t, util.IsObjectExists(cl, types.NamespacedName{Name: deploy.DevfileRegistryName, Namespace: checluster.Namespace}, &corev1.ConfigMap{}))
|
||||
assert.True(t, util.IsObjectExists(cl, types.NamespacedName{Name: deploy.PluginRegistryName, Namespace: checluster.Namespace}, &corev1.ConfigMap{}))
|
||||
|
||||
// reade checluster
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: os.Getenv("CHE_FLAVOR"), Namespace: namespace}, checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// update CR and make sure Che configmap has been updated
|
||||
checluster.Spec.Server.TlsSupport = true
|
||||
err = cl.Update(context.TODO(), checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// reconcile several times
|
||||
reconcileLoops := 4
|
||||
for i := 0; i < reconcileLoops; i++ {
|
||||
_, err = r.Reconcile(context.TODO(), req)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// get configmap
|
||||
cm := &corev1.ConfigMap{}
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: "che", Namespace: checluster.Namespace}, cm)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, cm.Data["CHE_INFRA_OPENSHIFT_TLS__ENABLED"], "true")
|
||||
|
||||
// Custom ConfigMap should be gone
|
||||
assert.False(t, util.IsObjectExists(cl, types.NamespacedName{Name: "custom", Namespace: checluster.Namespace}, &corev1.ConfigMap{}))
|
||||
|
||||
// Get the custom role binding that should have been created for the role we passed in
|
||||
assert.True(t, util.IsObjectExists(cl, types.NamespacedName{Name: "che-workspace-custom", Namespace: checluster.Namespace}, &rbacv1.RoleBinding{}))
|
||||
|
||||
route := &routev1.Route{}
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: deploy.DefaultCheFlavor(checluster), Namespace: checluster.Namespace}, route)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, route.Spec.TLS.Termination, routev1.TLSTerminationType("edge"))
|
||||
|
||||
// reread checluster
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: os.Getenv("CHE_FLAVOR"), Namespace: namespace}, checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// update CR and make sure Che configmap has been updated
|
||||
checluster.Spec.Auth.OpenShiftoAuth = util.NewBoolPointer(true)
|
||||
err = cl.Update(context.TODO(), checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = r.Reconcile(context.TODO(), req)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// get configmap and check if identity provider name and workspace project name are correctly set
|
||||
cm = &corev1.ConfigMap{}
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: "che", Namespace: checluster.Namespace}, cm)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, cm.Data["CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"], "openshift-v4")
|
||||
|
||||
// reread checluster
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: os.Getenv("CHE_FLAVOR"), Namespace: namespace}, checluster)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, util.IsObjectExists(cl, types.NamespacedName{Name: checluster.Spec.Auth.OAuthClientName}, &oauthv1.OAuthClient{}))
|
||||
|
||||
// check if a new Postgres deployment is not created when spec.Database.ExternalDB is true
|
||||
checluster.Spec.Database.ExternalDb = true
|
||||
err = cl.Update(context.TODO(), checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
postgresDeployment := &appsv1.Deployment{}
|
||||
err = r.client.Get(context.TODO(), types.NamespacedName{Name: deploy.PostgresName, Namespace: checluster.Namespace}, postgresDeployment)
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = r.client.Delete(context.TODO(), postgresDeployment)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = r.Reconcile(context.TODO(), req)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.False(t, util.IsObjectExists(cl, types.NamespacedName{Name: deploy.PostgresName, Namespace: checluster.Namespace}, &appsv1.Deployment{}))
|
||||
|
||||
// check of storageClassName ends up in pvc spec
|
||||
fakeStorageClassName := "fake-storage-class-name"
|
||||
checluster.Spec.Storage.PostgresPVCStorageClassName = fakeStorageClassName
|
||||
checluster.Spec.Database.ExternalDb = false
|
||||
err = r.client.Update(context.TODO(), checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
pvc := &corev1.PersistentVolumeClaim{}
|
||||
err = r.client.Get(context.TODO(), types.NamespacedName{Name: deploy.DefaultPostgresVolumeClaimName, Namespace: checluster.Namespace}, pvc)
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = r.client.Delete(context.TODO(), pvc)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = r.Reconcile(context.TODO(), req)
|
||||
assert.Nil(t, err)
|
||||
|
||||
pvc = &corev1.PersistentVolumeClaim{}
|
||||
err = r.client.Get(context.TODO(), types.NamespacedName{Name: deploy.DefaultPostgresVolumeClaimName, Namespace: checluster.Namespace}, pvc)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, fakeStorageClassName, *pvc.Spec.StorageClassName)
|
||||
|
||||
// reread checluster
|
||||
err = cl.Get(context.TODO(), types.NamespacedName{Name: os.Getenv("CHE_FLAVOR"), Namespace: namespace}, checluster)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "https://eclipse.org", checluster.Status.CheURL)
|
||||
|
||||
// check if oAuthClient is deleted after CR is deleted (finalizer logic)
|
||||
// since fake api does not set deletion timestamp, CR is updated in tests rather than deleted
|
||||
deletionTimestamp := &metav1.Time{Time: time.Now()}
|
||||
checluster.DeletionTimestamp = deletionTimestamp
|
||||
err = r.client.Update(context.TODO(), checluster)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = r.Reconcile(context.TODO(), req)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.False(t, util.IsObjectExists(cl, types.NamespacedName{Name: checluster.Spec.Auth.OAuthClientName}, &oauthv1.OAuthClient{}))
|
||||
}
|
||||
|
||||
func Init() (client.Client, discovery.DiscoveryInterface, runtime.Scheme) {
|
||||
objs, ds, scheme := createAPIObjects()
|
||||
|
||||
oAuth := &configv1.OAuth{}
|
||||
oAuthClient := &oauthv1.OAuthClient{}
|
||||
users := &userv1.UserList{}
|
||||
user := &userv1.User{}
|
||||
|
||||
// Register operator types with the runtime scheme
|
||||
scheme.AddKnownTypes(oauthv1.SchemeGroupVersion, oAuth)
|
||||
scheme.AddKnownTypes(oauthv1.SchemeGroupVersion, oAuthClient)
|
||||
scheme.AddKnownTypes(userv1.SchemeGroupVersion, users, user)
|
||||
scheme.AddKnownTypes(configv1.SchemeGroupVersion, &configv1.Proxy{})
|
||||
|
||||
// Create a fake client to mock API calls
|
||||
return fake.NewFakeClient(objs...), ds, scheme
|
||||
}
|
||||
|
||||
func createAPIObjects() ([]runtime.Object, discovery.DiscoveryInterface, runtime.Scheme) {
|
||||
pgPod := &corev1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fake-pg-pod",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
"component": deploy.PostgresName,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// A CheCluster custom resource with metadata and spec
|
||||
cheCR := &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: os.Getenv("CHE_FLAVOR"),
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CheHost: "eclipse.org",
|
||||
CheWorkspaceClusterRole: "cluster-admin",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
route := &routev1.Route{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deploy.DefaultCheFlavor(cheCR),
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
|
||||
packageManifest := &packagesv1.PackageManifest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "kubernetes-imagepuller-operator",
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
|
||||
oAuth := &configv1.OAuth{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cluster",
|
||||
},
|
||||
}
|
||||
|
||||
// Objects to track in the fake client.
|
||||
objs := []runtime.Object{
|
||||
cheCR, pgPod, route, packageManifest, oAuth,
|
||||
}
|
||||
|
||||
// Register operator types with the runtime scheme
|
||||
scheme := scheme.Scheme
|
||||
scheme.AddKnownTypes(orgv1.GroupVersion, cheCR)
|
||||
scheme.AddKnownTypes(routev1.SchemeGroupVersion, route)
|
||||
scheme.AddKnownTypes(console.GroupVersion, &console.ConsoleLink{})
|
||||
chev1alpha1.AddToScheme(scheme)
|
||||
packagesv1.AddToScheme(scheme)
|
||||
operatorsv1.AddToScheme(scheme)
|
||||
operatorsv1alpha1.AddToScheme(scheme)
|
||||
|
||||
cli := fakeclientset.NewSimpleClientset()
|
||||
fakeDiscovery, ok := cli.Discovery().(*fakeDiscovery.FakeDiscovery)
|
||||
if !ok {
|
||||
logrus.Error("Error creating fake discovery client")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create a fake client to mock API calls
|
||||
return objs, fakeDiscovery, *scheme
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ func (v *CheClusterValidator) Reconcile(ctx *deploy.DeployContext) (reconcile.Re
|
|||
}
|
||||
}
|
||||
|
||||
workspaceNamespaceDefault := util.GetWorkspaceNamespaceDefault(ctx.CheCluster)
|
||||
workspaceNamespaceDefault := deploy.GetWorkspaceNamespaceDefault(ctx.CheCluster)
|
||||
if strings.Index(workspaceNamespaceDefault, "<username>") == -1 && strings.Index(workspaceNamespaceDefault, "<userid>") == -1 {
|
||||
return reconcile.Result{}, false, fmt.Errorf(NamespaceStrategyErrorMessage, workspaceNamespaceDefault)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,6 @@ func GetProxyConfiguration(deployContext *deploy.DeployContext) (*deploy.Proxy,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if deployContext.CheCluster.IsInternalClusterSVCNamesEnabled() {
|
||||
cheClusterProxyConf.NoProxy = deploy.MergeNonProxy(cheClusterProxyConf.NoProxy, ".svc")
|
||||
}
|
||||
cheClusterProxyConf.NoProxy = deploy.MergeNonProxy(cheClusterProxyConf.NoProxy, ".svc")
|
||||
return cheClusterProxyConf, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import (
|
|||
fakeDiscovery "k8s.io/client-go/discovery/fake"
|
||||
fakeclientset "k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/utils/pointer"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
|
@ -250,10 +249,9 @@ func TestReadProxyConfiguration(t *testing.T) {
|
|||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
ProxyURL: "http://proxy",
|
||||
ProxyPort: "3128",
|
||||
NonProxyHosts: "host1",
|
||||
ProxyURL: "http://proxy",
|
||||
ProxyPort: "3128",
|
||||
NonProxyHosts: "host1",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -269,7 +267,7 @@ func TestReadProxyConfiguration(t *testing.T) {
|
|||
HttpsPassword: "",
|
||||
HttpsHost: "proxy",
|
||||
HttpsPort: "3128",
|
||||
NoProxy: "host1",
|
||||
NoProxy: "host1,.svc",
|
||||
TrustedCAMapName: "",
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -163,9 +163,6 @@ func backupDatabases(bctx *BackupContext, destDir string) (bool, error) {
|
|||
databasesToBackup := []string{
|
||||
bctx.cheCR.Spec.Database.ChePostgresDb,
|
||||
}
|
||||
if !bctx.cheCR.Spec.DevWorkspace.Enable {
|
||||
databasesToBackup = append(databasesToBackup, "keycloak")
|
||||
}
|
||||
|
||||
k8sClient := util.GetK8Client()
|
||||
postgresPodName, err := k8sClient.GetDeploymentPod(deploy.PostgresName, bctx.namespace)
|
||||
|
|
@ -256,12 +253,6 @@ func backupSecrets(bctx *BackupContext, destDir string) (bool, error) {
|
|||
if bctx.cheCR.Spec.Database.ChePostgresSecret != "" {
|
||||
secretsNames = append(secretsNames, bctx.cheCR.Spec.Database.ChePostgresSecret)
|
||||
}
|
||||
if bctx.cheCR.Spec.Auth.IdentityProviderPostgresSecret != "" {
|
||||
secretsNames = append(secretsNames, bctx.cheCR.Spec.Auth.IdentityProviderPostgresSecret)
|
||||
}
|
||||
if bctx.cheCR.Spec.Auth.IdentityProviderSecret != "" {
|
||||
secretsNames = append(secretsNames, bctx.cheCR.Spec.Auth.IdentityProviderSecret)
|
||||
}
|
||||
|
||||
// Retrieve and save each secret
|
||||
for _, secretName := range secretsNames {
|
||||
|
|
|
|||
|
|
@ -111,14 +111,6 @@ func RestoreChe(rctx *RestoreContext, dataDir string) (bool, error) {
|
|||
return done, err
|
||||
}
|
||||
|
||||
if !rctx.cheCR.Spec.DevWorkspace.Enable {
|
||||
// After Keycloak's database restoring, it is required to restart Keycloak to invalidate its cache.
|
||||
done, err = deleteKeycloakPod(rctx)
|
||||
if err != nil || !done {
|
||||
return done, err
|
||||
}
|
||||
}
|
||||
|
||||
rctx.state.cheDatabaseRestored = true
|
||||
if err := rctx.UpdateRestoreStatus(); err != nil {
|
||||
return false, err
|
||||
|
|
@ -238,24 +230,6 @@ func waitPreviousInstallationDeleted(rctx *RestoreContext) (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func deleteKeycloakPod(rctx *RestoreContext) (bool, error) {
|
||||
k8sClient := util.GetK8Client()
|
||||
keycloakPodName, err := k8sClient.GetDeploymentPod(deploy.IdentityProviderName, rctx.namespace)
|
||||
if err != nil {
|
||||
// Keycloak pod is already deleted, just skip it
|
||||
return true, nil
|
||||
}
|
||||
keycloakPodNsN := types.NamespacedName{Name: keycloakPodName, Namespace: rctx.namespace}
|
||||
keycloakPod := &corev1.Pod{}
|
||||
if err := rctx.r.nonCachingClient.Get(context.TODO(), keycloakPodNsN, keycloakPod); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := rctx.r.nonCachingClient.Delete(context.TODO(), keycloakPod); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func restoreCheResources(rctx *RestoreContext, dataDir string) (bool, error) {
|
||||
partsToRestore := []func(*RestoreContext, string) (bool, error){
|
||||
restoreConfigMaps,
|
||||
|
|
@ -406,10 +380,6 @@ func readAndAdaptCheCRFromBackup(rctx *RestoreContext, dataDir string) (*chev1.C
|
|||
cheCR.Spec.Server.CheHost = ""
|
||||
}
|
||||
}
|
||||
if !cheCR.Spec.Auth.ExternalIdentityProvider {
|
||||
// Let operator set the URL automatically
|
||||
cheCR.Spec.Auth.IdentityProviderURL = ""
|
||||
}
|
||||
|
||||
return cheCR, true, nil
|
||||
}
|
||||
|
|
@ -466,7 +436,6 @@ func dropDatabases(rctx *RestoreContext) {
|
|||
|
||||
databasesToDrop := []string{
|
||||
rctx.cheCR.Spec.Database.ChePostgresDb,
|
||||
"keycloak",
|
||||
}
|
||||
|
||||
k8sClient := util.GetK8Client()
|
||||
|
|
@ -525,24 +494,6 @@ func restoreDatabase(rctx *RestoreContext, dataDir string) (bool, error) {
|
|||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
if rctx.cheCR.Spec.Server.ServerExposureStrategy == "multi-host" {
|
||||
// Some databases contain values bind to cluster and/or namespace
|
||||
// These values should be adjusted according to new environmant.
|
||||
pathcDatabaseScript, err := getPatchDatabaseScript(rctx, dbName, dataDir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if pathcDatabaseScript != "" {
|
||||
execReason := fmt.Sprintf("patching %s database", dbName)
|
||||
if output, err := k8sClient.DoExecIntoPod(rctx.namespace, postgresPodName, pathcDatabaseScript, execReason); err != nil {
|
||||
if output != "" {
|
||||
logrus.Error(output)
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -565,8 +516,6 @@ func getDatabaseOwner(rctx *RestoreContext, dbName string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
return string(secret.Data["user"]), nil
|
||||
case "keycloak":
|
||||
return "keycloak", nil
|
||||
default:
|
||||
return "postgres", nil
|
||||
}
|
||||
|
|
@ -616,14 +565,6 @@ func getPatchDatabaseScript(rctx *RestoreContext, dbName string, dataDir string)
|
|||
script += "\n" + getReplaceInColumnScript(dbName, "devfile_project", "location", oldAppsSubStr, newAppsSubStr)
|
||||
}
|
||||
return script, nil
|
||||
case "keycloak":
|
||||
if !shouldPatchUrls {
|
||||
// No need to do anything, restoring into the same cluster and the same namespace
|
||||
break
|
||||
}
|
||||
script := getReplaceInColumnScript(dbName, "redirect_uris", "value", oldAppsSubStr, newAppsSubStr) + "\n" +
|
||||
getReplaceInColumnScript(dbName, "web_origins", "value", oldAppsSubStr, newAppsSubStr)
|
||||
return script, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,14 +57,16 @@ spec:
|
|||
used by the Che installation.
|
||||
properties:
|
||||
debug:
|
||||
description: Debug internal identity provider.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Debug internal identity provider.
|
||||
type: boolean
|
||||
externalIdentityProvider:
|
||||
description: 'Instructs the Operator on whether or not to deploy
|
||||
a dedicated Identity Provider (Keycloak or RH SSO instance).
|
||||
Instructs the Operator on whether to deploy a dedicated Identity
|
||||
Provider (Keycloak or RH-SSO instance). By default, a dedicated
|
||||
Identity Provider server is deployed as part of the Che installation.
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Instructs the Operator on whether or not to deploy a dedicated
|
||||
Identity Provider (Keycloak or RH SSO instance). Instructs
|
||||
the Operator on whether to deploy a dedicated Identity Provider
|
||||
(Keycloak or RH-SSO instance). By default, a dedicated Identity
|
||||
Provider server is deployed as part of the Che installation.
|
||||
When `externalIdentityProvider` is `true`, no dedicated identity
|
||||
provider will be deployed by the Operator and you will need
|
||||
to provide details about the external identity provider you
|
||||
|
|
@ -86,18 +88,21 @@ spec:
|
|||
Sidecar functionality is now implemented in Traefik plugin.
|
||||
type: string
|
||||
identityProviderAdminUserName:
|
||||
description: Overrides the name of the Identity Provider administrator
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the name of the Identity Provider administrator
|
||||
user. Defaults to `admin`.
|
||||
type: string
|
||||
identityProviderClientId:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO,
|
||||
`client-id` that is used for Che. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to the value
|
||||
of the `flavour` field suffixed with `-public`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Name of a Identity provider, Keycloak or RH-SSO, `client-id`
|
||||
that is used for Che. Override this when an external Identity
|
||||
Provider is in use. See the `externalIdentityProvider` field.
|
||||
When omitted or left blank, it is set to the value of the
|
||||
`flavour` field suffixed with `-public`.
|
||||
type: string
|
||||
identityProviderContainerResources:
|
||||
description: Identity provider container custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Identity provider container custom settings.
|
||||
properties:
|
||||
limits:
|
||||
description: Limits describes the maximum amount of compute
|
||||
|
|
@ -125,19 +130,22 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
identityProviderImage:
|
||||
description: Overrides the container image used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. This includes the
|
||||
image tag. Omit it or leave it empty to use the default container
|
||||
image provided by the Operator.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the container image used in the Identity Provider,
|
||||
Keycloak or RH-SSO, deployment. This includes the image tag.
|
||||
Omit it or leave it empty to use the default container image
|
||||
provided by the Operator.
|
||||
type: string
|
||||
identityProviderImagePullPolicy:
|
||||
description: Overrides the image pull policy used in the Identity
|
||||
Provider, Keycloak or RH-SSO, deployment. Default value is
|
||||
`Always` for `nightly`, `next` or `latest` images, and `IfNotPresent`
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the image pull policy used in the Identity Provider,
|
||||
Keycloak or RH-SSO, deployment. Default value is `Always`
|
||||
for `nightly`, `next` or `latest` images, and `IfNotPresent`
|
||||
in other cases.
|
||||
type: string
|
||||
identityProviderIngress:
|
||||
description: Ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -153,25 +161,27 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderPassword:
|
||||
description: Overrides the password of Keycloak administrator
|
||||
user. Override this when an external Identity Provider is
|
||||
in use. See the `externalIdentityProvider` field. When omitted
|
||||
or left blank, it is set to an auto-generated password.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Overrides the password of Keycloak administrator user. Override
|
||||
this when an external Identity Provider is in use. See the
|
||||
`externalIdentityProvider` field. When omitted or left blank,
|
||||
it is set to an auto-generated password.
|
||||
type: string
|
||||
identityProviderPostgresPassword:
|
||||
description: Password for a Identity Provider, Keycloak or RH-SSO,
|
||||
to connect to the database. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to an auto-generated
|
||||
password.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Password for a Identity Provider, Keycloak or RH-SSO, to connect
|
||||
to the database. Override this when an external Identity Provider
|
||||
is in use. See the `externalIdentityProvider` field. When
|
||||
omitted or left blank, it is set to an auto-generated password.
|
||||
type: string
|
||||
identityProviderPostgresSecret:
|
||||
description: 'The secret that contains `password` for the Identity
|
||||
Provider, Keycloak or RH-SSO, to connect to the database.
|
||||
When the secret is defined, the `identityProviderPostgresPassword`
|
||||
is ignored. When the value is omitted or left blank, the one
|
||||
of following scenarios applies: 1. `identityProviderPostgresPassword`
|
||||
is defined, then it will be used to connect to the database.
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
The secret that contains `password` for the Identity Provider,
|
||||
Keycloak or RH-SSO, to connect to the database. When the secret
|
||||
is defined, the `identityProviderPostgresPassword` is ignored.
|
||||
When the value is omitted or left blank, the one of following
|
||||
scenarios applies: 1. `identityProviderPostgresPassword` is
|
||||
defined, then it will be used to connect to the database.
|
||||
2. `identityProviderPostgresPassword` is not defined, then
|
||||
a new secret with the name `che-identity-postgres-secret`
|
||||
will be created with an auto-generated value for `password`.
|
||||
|
|
@ -179,14 +189,16 @@ spec:
|
|||
label.'
|
||||
type: string
|
||||
identityProviderRealm:
|
||||
description: Name of a Identity provider, Keycloak or RH-SSO,
|
||||
realm that is used for Che. Override this when an external
|
||||
Identity Provider is in use. See the `externalIdentityProvider`
|
||||
field. When omitted or left blank, it is set to the value
|
||||
of the `flavour` field.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Name of a Identity provider, Keycloak or RH-SSO, realm that
|
||||
is used for Che. Override this when an external Identity Provider
|
||||
is in use. See the `externalIdentityProvider` field. When
|
||||
omitted or left blank, it is set to the value of the `flavour`
|
||||
field.
|
||||
type: string
|
||||
identityProviderRoute:
|
||||
description: Route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -208,8 +220,9 @@ spec:
|
|||
type: string
|
||||
type: object
|
||||
identityProviderSecret:
|
||||
description: 'The secret that contains `user` and `password`
|
||||
for Identity Provider. When the secret is defined, the `identityProviderAdminUserName`
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
The secret that contains `user` and `password` for Identity
|
||||
Provider. When the secret is defined, the `identityProviderAdminUserName`
|
||||
and `identityProviderPassword` are ignored. When the value
|
||||
is omitted or left blank, the one of following scenarios applies:
|
||||
1. `identityProviderAdminUserName` and `identityProviderPassword`
|
||||
|
|
@ -228,20 +241,22 @@ spec:
|
|||
set by the Operator.
|
||||
type: string
|
||||
initialOpenShiftOAuthUser:
|
||||
description: For operating with the OpenShift OAuth authentication,
|
||||
create a new user account since the kubeadmin can not be used.
|
||||
If the value is true, then a new OpenShift OAuth user will
|
||||
be created for the HTPasswd identity provider. If the value
|
||||
is false and the user has already been created, then it will
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
For operating with the OpenShift OAuth authentication, create
|
||||
a new user account since the kubeadmin can not be used. If
|
||||
the value is true, then a new OpenShift OAuth user will be
|
||||
created for the HTPasswd identity provider. If the value is
|
||||
false and the user has already been created, then it will
|
||||
be removed. If value is an empty, then do nothing. The user's
|
||||
credentials are stored in the `openshift-oauth-user-credentials`
|
||||
secret in 'openshift-config' namespace by Operator. Note that
|
||||
this solution is Openshift 4 platform-specific.
|
||||
type: boolean
|
||||
nativeUserMode:
|
||||
description: Enables native user mode. Currently works only
|
||||
on OpenShift and DevWorkspace engine. Native User mode uses
|
||||
OpenShift OAuth directly as identity provider, without Keycloak.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Enables native user mode. Currently works only on OpenShift
|
||||
and DevWorkspace engine. Native User mode uses OpenShift OAuth
|
||||
directly as identity provider, without Keycloak.
|
||||
type: boolean
|
||||
oAuthClientName:
|
||||
description: Name of the OpenShift `OAuthClient` resource used
|
||||
|
|
@ -255,17 +270,19 @@ spec:
|
|||
field.
|
||||
type: string
|
||||
openShiftoAuth:
|
||||
description: 'Enables the integration of the identity provider
|
||||
(Keycloak / RHSSO) with OpenShift OAuth. Empty value on OpenShift
|
||||
by default. This will allow users to directly login with their
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Enables the integration of the identity provider (Keycloak
|
||||
/ RHSSO) with OpenShift OAuth. Empty value on OpenShift by
|
||||
default. This will allow users to directly login with their
|
||||
OpenShift user through the OpenShift login, and have their
|
||||
workspaces created under personal OpenShift namespaces. WARNING:
|
||||
the `kubeadmin` user is NOT supported, and logging through
|
||||
it will NOT allow accessing the Che Dashboard.'
|
||||
type: boolean
|
||||
updateAdminPassword:
|
||||
description: Forces the default `admin` Che user to update password
|
||||
on first login. Defaults to `false`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Forces the default `admin` Che user to update password on
|
||||
first login. Defaults to `false`.
|
||||
type: boolean
|
||||
type: object
|
||||
database:
|
||||
|
|
@ -452,10 +469,11 @@ spec:
|
|||
This MUST be explicitly specified: there are no defaults.'
|
||||
type: string
|
||||
ingressStrategy:
|
||||
description: 'Strategy for ingress creation. Options are: `multi-host`
|
||||
(host is explicitly provided in ingress), `single-host` (host
|
||||
is provided, path-based rules) and `default-host` (no host
|
||||
is provided, path-based rules). Defaults to `multi-host` Deprecated
|
||||
description: 'Deprecated. The value of this flag is ignored.
|
||||
Strategy for ingress creation. Options are: `multi-host` (host
|
||||
is explicitly provided in ingress), `single-host` (host is
|
||||
provided, path-based rules) and `default-host` (no host is
|
||||
provided, path-based rules). Defaults to `multi-host` Deprecated
|
||||
in favor of `serverExposureStrategy` in the `server` section,
|
||||
which defines this regardless of the cluster type. When both
|
||||
are defined, the `serverExposureStrategy` option takes precedence.'
|
||||
|
|
@ -469,15 +487,16 @@ spec:
|
|||
run as. Default value is `1724`.
|
||||
type: string
|
||||
singleHostExposureType:
|
||||
description: When the serverExposureStrategy is set to `single-host`,
|
||||
the way the server, registries and workspaces are exposed
|
||||
is further configured by this property. The possible values
|
||||
are `native`, which means that the server and workspaces are
|
||||
exposed using ingresses on K8s or `gateway` where the server
|
||||
and workspaces are exposed using a custom gateway based on
|
||||
link:https://doc.traefik.io/traefik/[Traefik]. All the endpoints
|
||||
whether backed by the ingress or gateway `route` always point
|
||||
to the subpaths on the same domain. Defaults to `native`.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
When the serverExposureStrategy is set to `single-host`, the
|
||||
way the server, registries and workspaces are exposed is further
|
||||
configured by this property. The possible values are `native`,
|
||||
which means that the server and workspaces are exposed using
|
||||
ingresses on K8s or `gateway` where the server and workspaces
|
||||
are exposed using a custom gateway based on link:https://doc.traefik.io/traefik/[Traefik].
|
||||
All the endpoints whether backed by the ingress or gateway
|
||||
`route` always point to the subpaths on the same domain. Defaults
|
||||
to `native`.
|
||||
type: string
|
||||
tlsSecretName:
|
||||
description: Name of a secret that will be used to setup ingress
|
||||
|
|
@ -531,9 +550,9 @@ spec:
|
|||
to `false`.
|
||||
type: string
|
||||
cheFlavor:
|
||||
description: Specifies a variation of the installation. The
|
||||
options are `che` for upstream Che installations, or `codeready`
|
||||
for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Specifies a variation of the installation. The options are
|
||||
`che` for upstream Che installations, or `codeready` for link:https://developers.redhat.com/products/codeready-workspaces/overview[CodeReady
|
||||
Workspaces] installation. Override the default value only
|
||||
on necessary occasions.
|
||||
type: string
|
||||
|
|
@ -642,7 +661,8 @@ spec:
|
|||
or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
dashboardIngress:
|
||||
description: Dashboard ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Dashboard ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -666,7 +686,8 @@ spec:
|
|||
deployment. Defaults to 16Mi.
|
||||
type: string
|
||||
dashboardRoute:
|
||||
description: Dashboard route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Dashboard route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -702,7 +723,8 @@ spec:
|
|||
by the Operator.
|
||||
type: string
|
||||
devfileRegistryIngress:
|
||||
description: The devfile registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
The devfile registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -731,7 +753,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
devfileRegistryRoute:
|
||||
description: The devfile registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
The devfile registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -757,9 +780,9 @@ spec:
|
|||
fields.
|
||||
type: string
|
||||
disableInternalClusterSVCNames:
|
||||
description: Disable internal cluster SVC names usage to communicate
|
||||
between components to speed up the traffic and avoid proxy
|
||||
issues.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Disable internal cluster SVC names usage to communicate between
|
||||
components to speed up the traffic and avoid proxy issues.
|
||||
type: boolean
|
||||
externalDevfileRegistries:
|
||||
description: External devfile registries, that serves sample,
|
||||
|
|
@ -824,7 +847,8 @@ spec:
|
|||
by the Operator.
|
||||
type: string
|
||||
pluginRegistryIngress:
|
||||
description: Plugin registry ingress custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Plugin registry ingress custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -853,7 +877,8 @@ spec:
|
|||
`next` or `latest` images, and `IfNotPresent` in other cases.
|
||||
type: string
|
||||
pluginRegistryRoute:
|
||||
description: Plugin registry route custom settings.
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Plugin registry route custom settings.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
|
|
@ -929,8 +954,9 @@ spec:
|
|||
deployment In cores. (500m = .5 cores). Default to 100m.
|
||||
type: string
|
||||
serverExposureStrategy:
|
||||
description: Sets the server and workspaces exposure type. Possible
|
||||
values are `multi-host`, `single-host`, `default-host`. Defaults
|
||||
description: Deprecated. The value of this flag is ignored.
|
||||
Sets the server and workspaces exposure type. Possible values
|
||||
are `multi-host`, `single-host`, `default-host`. Defaults
|
||||
to `multi-host`, which creates a separate ingress, or OpenShift
|
||||
routes, for every required endpoint. `single-host` makes Che
|
||||
exposed on a single host name with workspaces exposed on subpaths.
|
||||
|
|
|
|||
|
|
@ -77,8 +77,6 @@ spec:
|
|||
value: quay.io/eclipse/che--centos--postgresql-96-centos7:9.6-b681d78125361519180a6ac05242c296f8906c11eab7e207b5ca9a89b6344392
|
||||
- name: RELATED_IMAGE_postgres_13_3
|
||||
value: quay.io/eclipse/che--centos--postgresql-13-centos7:1-71b24684d64da46f960682cc4216222a7e4ed8b1a31dd5a865b3e71afdea20d2
|
||||
- name: RELATED_IMAGE_keycloak
|
||||
value: quay.io/eclipse/che-keycloak:next
|
||||
- name: RELATED_IMAGE_che_workspace_plugin_broker_metadata
|
||||
value: quay.io/eclipse/che-plugin-metadata-broker:v3.4.0
|
||||
- name: RELATED_IMAGE_che_workspace_plugin_broker_artifacts
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ spec:
|
|||
cheClusterRoles: ''
|
||||
cheWorkspaceClusterRole: ''
|
||||
gitSelfSignedCert: false
|
||||
tlsSupport: true
|
||||
proxyURL: ''
|
||||
proxyPort: ''
|
||||
proxySecret: ''
|
||||
|
|
|
|||
|
|
@ -44,12 +44,6 @@ func (c *ConsoleLinkReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile.
|
|||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
if !ctx.CheCluster.Spec.Server.TlsSupport {
|
||||
// console link is supported only with https
|
||||
logrus.Debug("Console link won't be created. HTTP protocol is not supported.")
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
done, err := c.createConsoleLink(ctx)
|
||||
if !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
|
|
|
|||
|
|
@ -31,11 +31,7 @@ func TestReconcileConsoleLink(t *testing.T) {
|
|||
Namespace: "eclipse-che",
|
||||
Name: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
TlsSupport: true,
|
||||
},
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{},
|
||||
}
|
||||
|
||||
util.IsOpenShift4 = true
|
||||
|
|
|
|||
|
|
@ -57,8 +57,6 @@ func (d *DashboardReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile.Re
|
|||
// Expose dashboard service with route or ingress
|
||||
_, done, err = expose.ExposeWithHostPath(ctx, d.getComponentName(ctx), ctx.CheCluster.Spec.Server.CheHost,
|
||||
exposePath,
|
||||
ctx.CheCluster.Spec.Server.DashboardRoute,
|
||||
ctx.CheCluster.Spec.Server.DashboardIngress,
|
||||
d.createGatewayConfig(ctx),
|
||||
)
|
||||
if !done {
|
||||
|
|
@ -130,7 +128,7 @@ func (d *DashboardReconciler) createGatewayConfig(ctx *deploy.DeployContext) *ga
|
|||
10,
|
||||
"http://"+d.getComponentName(ctx)+":8080",
|
||||
[]string{})
|
||||
if util.IsOpenShift && ctx.CheCluster.IsNativeUserModeEnabled() {
|
||||
if util.IsOpenShift {
|
||||
cfg.AddAuthHeaderRewrite(d.getComponentName(ctx))
|
||||
}
|
||||
return cfg
|
||||
|
|
|
|||
|
|
@ -122,19 +122,18 @@ func TestDashboardDeploymentEnvVars(t *testing.T) {
|
|||
envVars []corev1.EnvVar
|
||||
cheCluster *orgv1.CheCluster
|
||||
}
|
||||
trueBool := true
|
||||
testCases := []resourcesTestCase{
|
||||
{
|
||||
name: "Test provisioning Che and Keycloak URLs",
|
||||
name: "Test provisioning Che URLs",
|
||||
initObjects: []runtime.Object{},
|
||||
envVars: []corev1.EnvVar{
|
||||
{
|
||||
Name: "CHE_HOST",
|
||||
Value: "http://che.com",
|
||||
Value: "https://che.com",
|
||||
},
|
||||
{
|
||||
Name: "CHE_URL",
|
||||
Value: "http://che.com",
|
||||
Value: "https://che.com",
|
||||
},
|
||||
{
|
||||
Name: "CHECLUSTER_CR_NAMESPACE",
|
||||
|
|
@ -164,44 +163,6 @@ func TestDashboardDeploymentEnvVars(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test provisioning Che and Keycloak URLs when internal SVC is disabled",
|
||||
initObjects: []runtime.Object{},
|
||||
envVars: []corev1.EnvVar{
|
||||
{
|
||||
Name: "CHE_HOST",
|
||||
Value: "http://che.com",
|
||||
},
|
||||
{
|
||||
Name: "CHE_URL",
|
||||
Value: "http://che.com",
|
||||
},
|
||||
{
|
||||
Name: "CHECLUSTER_CR_NAMESPACE",
|
||||
Value: "eclipse-che",
|
||||
},
|
||||
{
|
||||
Name: "CHECLUSTER_CR_NAME",
|
||||
Value: "eclipse-che",
|
||||
},
|
||||
{
|
||||
Name: "OPENSHIFT_CONSOLE_URL",
|
||||
},
|
||||
// the following are not provisioned: CHE_INTERNAL_URL
|
||||
},
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
Name: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: &trueBool,
|
||||
CheHost: "che.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test provisioning OpenShift Console URL",
|
||||
initObjects: []runtime.Object{
|
||||
|
|
@ -218,11 +179,11 @@ func TestDashboardDeploymentEnvVars(t *testing.T) {
|
|||
envVars: []corev1.EnvVar{
|
||||
{
|
||||
Name: "CHE_HOST",
|
||||
Value: "http://che.com",
|
||||
Value: "https://che.com",
|
||||
},
|
||||
{
|
||||
Name: "CHE_URL",
|
||||
Value: "http://che.com",
|
||||
Value: "https://che.com",
|
||||
},
|
||||
{
|
||||
Name: "CHECLUSTER_CR_NAMESPACE",
|
||||
|
|
|
|||
|
|
@ -16,11 +16,9 @@ import (
|
|||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
|
@ -40,7 +38,6 @@ func TestDashboardOpenShift(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &corev1.Service{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &routev1.Route{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &appsv1.Deployment{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: DashboardSA, Namespace: "eclipse-che"}, &corev1.ServiceAccount{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &appsv1.Deployment{}))
|
||||
|
|
@ -60,7 +57,6 @@ func TestDashboardKubernetes(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &corev1.Service{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &networkingv1.Ingress{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &appsv1.Deployment{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: DashboardSA, Namespace: "eclipse-che"}, &corev1.ServiceAccount{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: dashboard.getComponentName(ctx), Namespace: "eclipse-che"}, &appsv1.Deployment{}))
|
||||
|
|
|
|||
|
|
@ -64,13 +64,11 @@ func (d *DashboardReconciler) getDashboardDeploymentSpec(ctx *deploy.DeployConte
|
|||
Value: ctx.CheCluster.Name},
|
||||
)
|
||||
|
||||
if ctx.CheCluster.IsInternalClusterSVCNamesEnabled() {
|
||||
envVars = append(envVars,
|
||||
corev1.EnvVar{
|
||||
Name: "CHE_INTERNAL_URL",
|
||||
Value: fmt.Sprintf("http://%s.%s.svc:8080/api", deploy.CheServiceName, ctx.CheCluster.Namespace)},
|
||||
)
|
||||
}
|
||||
envVars = append(envVars,
|
||||
corev1.EnvVar{
|
||||
Name: "CHE_INTERNAL_URL",
|
||||
Value: fmt.Sprintf("http://%s.%s.svc:8080/api", deploy.CheServiceName, ctx.CheCluster.Namespace)},
|
||||
)
|
||||
|
||||
if util.IsOpenShift {
|
||||
envVars = append(envVars,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ var (
|
|||
defaultPvcJobsImage string
|
||||
defaultPostgresImage string
|
||||
defaultPostgres13Image string
|
||||
defaultKeycloakImage string
|
||||
defaultSingleHostGatewayImage string
|
||||
defaultSingleHostGatewayConfigSidecarImage string
|
||||
defaultInternalRestBackupServerImage string
|
||||
|
|
@ -63,7 +62,6 @@ const (
|
|||
DefaultPvcClaimSize = "10Gi"
|
||||
DefaultIngressClass = "nginx"
|
||||
|
||||
DefaultKeycloakAdminUserName = "admin"
|
||||
DefaultCheLogLevel = "INFO"
|
||||
DefaultCheDebug = "false"
|
||||
DefaultCheMetricsPort = int32(8087)
|
||||
|
|
@ -81,21 +79,9 @@ const (
|
|||
|
||||
KubernetesImagePullerOperatorCSV = "kubernetes-imagepuller-operator.v0.0.9"
|
||||
|
||||
DefaultServerExposureStrategy = "multi-host"
|
||||
NativeSingleHostExposureType = "native"
|
||||
ServerExposureStrategy = "single-host"
|
||||
GatewaySingleHostExposureType = "gateway"
|
||||
|
||||
// This is only to correctly manage defaults during the transition
|
||||
// from Upstream 7.0.0 GA to the next version
|
||||
// That fixed bug https://github.com/eclipse/che/issues/13714
|
||||
OldDefaultKeycloakUpstreamImageToDetect = "eclipse/che-keycloak:7.0.0"
|
||||
OldDefaultPvcJobsUpstreamImageToDetect = "registry.access.redhat.com/ubi8-minimal:8.0-127"
|
||||
OldDefaultPostgresUpstreamImageToDetect = "centos/postgresql-96-centos7:9.6"
|
||||
|
||||
OldDefaultCodeReadyServerImageRepo = "registry.redhat.io/codeready-workspaces/server-rhel8"
|
||||
OldDefaultCodeReadyServerImageTag = "1.2"
|
||||
OldCrwPluginRegistryUrl = "https://che-plugin-registry.openshift.io"
|
||||
|
||||
// kubernetes default labels
|
||||
KubernetesComponentLabelKey = "app.kubernetes.io/component"
|
||||
KubernetesPartOfLabelKey = "app.kubernetes.io/part-of"
|
||||
|
|
@ -118,10 +104,9 @@ const (
|
|||
CheEclipseOrgManagedAnnotationsDigest = "che.eclipse.org/managed-annotations-digest"
|
||||
|
||||
// components
|
||||
IdentityProviderName = "keycloak"
|
||||
DevfileRegistryName = "devfile-registry"
|
||||
PluginRegistryName = "plugin-registry"
|
||||
PostgresName = "postgres"
|
||||
DevfileRegistryName = "devfile-registry"
|
||||
PluginRegistryName = "plugin-registry"
|
||||
PostgresName = "postgres"
|
||||
|
||||
// CheServiceAccountName - service account name for che-server.
|
||||
CheServiceAccountName = "che"
|
||||
|
|
@ -198,7 +183,6 @@ func InitDefaultsFromFile(defaultsPath string) {
|
|||
defaultPvcJobsImage = util.GetDeploymentEnv(operatorDeployment, util.GetArchitectureDependentEnv("RELATED_IMAGE_pvc_jobs"))
|
||||
defaultPostgresImage = util.GetDeploymentEnv(operatorDeployment, util.GetArchitectureDependentEnv("RELATED_IMAGE_postgres"))
|
||||
defaultPostgres13Image = util.GetDeploymentEnv(operatorDeployment, util.GetArchitectureDependentEnv("RELATED_IMAGE_postgres_13_3"))
|
||||
defaultKeycloakImage = util.GetDeploymentEnv(operatorDeployment, util.GetArchitectureDependentEnv("RELATED_IMAGE_keycloak"))
|
||||
defaultSingleHostGatewayImage = util.GetDeploymentEnv(operatorDeployment, util.GetArchitectureDependentEnv("RELATED_IMAGE_single_host_gateway"))
|
||||
defaultSingleHostGatewayConfigSidecarImage = util.GetDeploymentEnv(operatorDeployment, util.GetArchitectureDependentEnv("RELATED_IMAGE_single_host_gateway_config_sidecar"))
|
||||
defaultGatewayAuthenticationSidecarImage = util.GetDeploymentEnv(operatorDeployment, util.GetArchitectureDependentEnv("RELATED_IMAGE_gateway_authentication_sidecar"))
|
||||
|
|
@ -246,15 +230,6 @@ func getDefaultFromEnv(envName string) string {
|
|||
return value
|
||||
}
|
||||
|
||||
func MigratingToCRW2_0(cr *orgv1.CheCluster) bool {
|
||||
if cr.Spec.Server.CheFlavor == "codeready" &&
|
||||
strings.HasPrefix(cr.Status.CheVersion, "1.2") &&
|
||||
strings.HasPrefix(defaultCheVersion, "2.0") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsComponentReadinessInitContainersConfigured(cr *orgv1.CheCluster) bool {
|
||||
return os.Getenv("ADD_COMPONENT_READINESS_INIT_CONTAINERS") == "true"
|
||||
}
|
||||
|
|
@ -264,7 +239,7 @@ func DefaultServerTrustStoreConfigMapName() string {
|
|||
}
|
||||
|
||||
func DefaultCheFlavor(cr *orgv1.CheCluster) string {
|
||||
return util.GetValue(cr.Spec.Server.CheFlavor, getDefaultFromEnv("CHE_FLAVOR"))
|
||||
return getDefaultFromEnv("CHE_FLAVOR")
|
||||
}
|
||||
|
||||
func DefaultConsoleLinkName() string {
|
||||
|
|
@ -331,10 +306,6 @@ func DefaultDevworkspaceControllerImage(cr *orgv1.CheCluster) string {
|
|||
return patchDefaultImageName(cr, defaultDevworkspaceControllerImage)
|
||||
}
|
||||
|
||||
func DefaultKeycloakImage(cr *orgv1.CheCluster) string {
|
||||
return patchDefaultImageName(cr, defaultKeycloakImage)
|
||||
}
|
||||
|
||||
func DefaultPluginRegistryImage(cr *orgv1.CheCluster) string {
|
||||
return patchDefaultImageName(cr, defaultPluginRegistryImage)
|
||||
}
|
||||
|
|
@ -395,12 +366,20 @@ func DefaultPullPolicyFromDockerImage(dockerImage string) string {
|
|||
return "IfNotPresent"
|
||||
}
|
||||
|
||||
func GetSingleHostExposureType(cr *orgv1.CheCluster) string {
|
||||
if util.IsOpenShift || cr.Spec.DevWorkspace.Enable {
|
||||
return GatewaySingleHostExposureType
|
||||
// GetWorkspaceNamespaceDefault - returns workspace namespace default strategy, which points on the namespaces used for workspaces execution.
|
||||
func GetWorkspaceNamespaceDefault(cr *orgv1.CheCluster) string {
|
||||
if cr.Spec.Server.CustomCheProperties != nil {
|
||||
k8sNamespaceDefault := cr.Spec.Server.CustomCheProperties["CHE_INFRA_KUBERNETES_NAMESPACE_DEFAULT"]
|
||||
if k8sNamespaceDefault != "" {
|
||||
return k8sNamespaceDefault
|
||||
}
|
||||
}
|
||||
|
||||
return util.GetValue(cr.Spec.K8s.SingleHostExposureType, NativeSingleHostExposureType)
|
||||
workspaceNamespaceDefault := cr.Namespace
|
||||
if util.IsOpenShift {
|
||||
workspaceNamespaceDefault = "<username>-" + DefaultCheFlavor(cr)
|
||||
}
|
||||
return util.GetValue(cr.Spec.Server.WorkspaceNamespaceDefault, workspaceNamespaceDefault)
|
||||
}
|
||||
|
||||
func patchDefaultImageName(cr *orgv1.CheCluster, imageName string) string {
|
||||
|
|
@ -474,7 +453,6 @@ func InitDefaultsFromEnv() {
|
|||
// while downstream is not migrated to PostgreSQL 13.3 yet
|
||||
defaultPostgres13Image = os.Getenv(util.GetArchitectureDependentEnv("RELATED_IMAGE_postgres_13_3"))
|
||||
|
||||
defaultKeycloakImage = os.Getenv(util.GetArchitectureDependentEnv("RELATED_IMAGE_keycloak"))
|
||||
defaultSingleHostGatewayImage = getDefaultFromEnv(util.GetArchitectureDependentEnv("RELATED_IMAGE_single_host_gateway"))
|
||||
defaultSingleHostGatewayConfigSidecarImage = getDefaultFromEnv(util.GetArchitectureDependentEnv("RELATED_IMAGE_single_host_gateway_config_sidecar"))
|
||||
defaultInternalRestBackupServerImage = getDefaultFromEnv(util.GetArchitectureDependentEnv("RELATED_IMAGE_internal_rest_backup_server"))
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ if [[ ! -f ${defaultsFile} ]]; then
|
|||
curl -ssL https://raw.githubusercontent.com/eclipse-che/che-operator/main/pkg/deploy/defaults.go -o ${defaultsFile}
|
||||
fi
|
||||
|
||||
excludes="eclipse/che-keycloak|centos/postgresql-96-centos7"
|
||||
for d in $(cat /tmp/defaults.go | egrep "Keycloak|Postgres|Pvc" | egrep Image | egrep -v "func|return|Old|ToDetect|$excludes" | sed -e "s#.\+= \"\(.\+\)\"#\1#"); do
|
||||
excludes="eclipse|centos/postgresql-96-centos7"
|
||||
for d in $(cat /tmp/defaults.go | egrep "Postgres|Pvc" | egrep Image | egrep -v "func|return|Old|ToDetect|$excludes" | sed -e "s#.\+= \"\(.\+\)\"#\1#"); do
|
||||
echo "- ${d}"
|
||||
echo -n "+ ${d%:*}:";
|
||||
e=$(skopeo inspect docker://${d%:*} | yq .RepoTags | egrep -v "\[|\]|latest" | tr -d ",\" " | sort -V | tail -1)
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ func TestCorrectAirGapPatchedImage(t *testing.T) {
|
|||
expectedAirGapPostgresUpstreamImageOnlyOrgChanged = makeAirGapImagePath(getHostnameFromImage(defaultPostgresImage), airGapRegistryOrganization, getImageNameFromFullImage(defaultPostgresImage))
|
||||
expectedAirGapCRWPluginRegistryOnlyOrgChanged = makeAirGapImagePath(getHostnameFromImage(defaultPluginRegistryImage), airGapRegistryOrganization, getImageNameFromFullImage(defaultPluginRegistryImage))
|
||||
expectedAirGapCRWPostgresImage = makeAirGapImagePath(airGapRegistryHostname, airGapRegistryOrganization, getImageNameFromFullImage(defaultPostgresImage))
|
||||
expectedAirGapKeyCloakImageOnlyHostnameChanged = makeAirGapImagePath(airGapRegistryHostname, getOrganizationFromImage(defaultKeycloakImage), getImageNameFromFullImage(defaultKeycloakImage))
|
||||
expectedAirGapCRWDevfileRegistryImageOnlyHostnameChanged = makeAirGapImagePath(airGapRegistryHostname, getOrganizationFromImage(defaultDevfileRegistryImage), getImageNameFromFullImage(defaultDevfileRegistryImage))
|
||||
)
|
||||
|
||||
|
|
@ -157,13 +156,6 @@ func TestCorrectAirGapPatchedImage(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
upstreamOnlyHostname := &orgv1.CheCluster{
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
AirGapContainerRegistryHostname: airGapRegistryHostname,
|
||||
},
|
||||
},
|
||||
}
|
||||
crwOnlyOrg := &orgv1.CheCluster{
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
|
|
@ -188,7 +180,6 @@ func TestCorrectAirGapPatchedImage(t *testing.T) {
|
|||
"codeready plugin registry with only the org changed": {image: defaultPluginRegistryImage, expected: expectedAirGapCRWPluginRegistryOnlyOrgChanged, cr: crwOnlyOrg},
|
||||
"CRW postgres": {image: defaultPostgresImage, expected: defaultPostgresImage, cr: crw},
|
||||
"CRW airgap postgres": {image: defaultPostgresImage, expected: expectedAirGapCRWPostgresImage, cr: airGapCRW},
|
||||
"airgap with only hostname defined": {image: defaultKeycloakImage, expected: expectedAirGapKeyCloakImageOnlyHostnameChanged, cr: upstreamOnlyHostname},
|
||||
"crw airgap with only hostname defined": {image: defaultDevfileRegistryImage, expected: expectedAirGapCRWDevfileRegistryImageOnlyHostnameChanged, cr: crwOnlyHostname},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
|
|
|
|||
|
|
@ -63,11 +63,6 @@ func (d *DevWorkspaceReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile
|
|||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
if !ctx.CheCluster.Spec.DevWorkspace.Enable {
|
||||
// Do nothing if DevWorkspace is disabled
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
if isDevWorkspaceOperatorCSVExists(ctx) {
|
||||
// Do nothing if DevWorkspace has been already deployed via OLM
|
||||
return reconcile.Result{}, true, nil
|
||||
|
|
|
|||
|
|
@ -59,19 +59,13 @@ func TestReconcileDevWorkspace(t *testing.T) {
|
|||
DevWorkspace: orgv1.CheClusterSpecDevWorkspace{
|
||||
Enable: true,
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(true),
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "single-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
IsOpenShift: true,
|
||||
IsOpenShift4: true,
|
||||
},
|
||||
{
|
||||
name: "Reconcile DevWorkspace on K8S multi-host",
|
||||
name: "Reconcile DevWorkspace on K8S",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
|
|
@ -80,37 +74,8 @@ func TestReconcileDevWorkspace(t *testing.T) {
|
|||
DevWorkspace: orgv1.CheClusterSpecDevWorkspace{
|
||||
Enable: true,
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(true),
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
CustomCheProperties: map[string]string{"CHE_INFRA_KUBERNETES_ENABLE__UNSUPPORTED__K8S": "true"},
|
||||
},
|
||||
K8s: orgv1.CheClusterSpecK8SOnly{
|
||||
IngressDomain: "che.domain",
|
||||
},
|
||||
},
|
||||
},
|
||||
IsOpenShift: false,
|
||||
IsOpenShift4: false,
|
||||
},
|
||||
{
|
||||
name: "Reconcile DevWorkspace on K8S single-host",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
DevWorkspace: orgv1.CheClusterSpecDevWorkspace{
|
||||
Enable: true,
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(true),
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "single-host",
|
||||
CustomCheProperties: map[string]string{"CHE_INFRA_KUBERNETES_ENABLE__UNSUPPORTED__K8S": "true"},
|
||||
CustomCheProperties: map[string]string{"CHE_INFRA_KUBERNETES_ENABLE__UNSUPPORTED__K8S": "true"},
|
||||
},
|
||||
K8s: orgv1.CheClusterSpecK8SOnly{
|
||||
IngressDomain: "che.domain",
|
||||
|
|
|
|||
|
|
@ -86,19 +86,11 @@ func (d *DevfileRegistryReconciler) exposeEndpoint(ctx *deploy.DeployContext) (s
|
|||
return expose.Expose(
|
||||
ctx,
|
||||
deploy.DevfileRegistryName,
|
||||
ctx.CheCluster.Spec.Server.DevfileRegistryRoute,
|
||||
ctx.CheCluster.Spec.Server.DevfileRegistryIngress,
|
||||
d.createGatewayConfig())
|
||||
}
|
||||
|
||||
func (d *DevfileRegistryReconciler) updateStatus(endpoint string, ctx *deploy.DeployContext) (bool, error) {
|
||||
var devfileRegistryURL string
|
||||
if ctx.CheCluster.Spec.Server.TlsSupport {
|
||||
devfileRegistryURL = "https://" + endpoint
|
||||
} else {
|
||||
devfileRegistryURL = "http://" + endpoint
|
||||
}
|
||||
|
||||
devfileRegistryURL := "https://" + endpoint
|
||||
if devfileRegistryURL != ctx.CheCluster.Status.DevfileRegistryURL {
|
||||
ctx.CheCluster.Status.DevfileRegistryURL = devfileRegistryURL
|
||||
if err := deploy.UpdateCheCRStatus(ctx, "status: Devfile Registry URL", devfileRegistryURL); err != nil {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ func (d *DevfileRegistryReconciler) getDevfileRegistryDeploymentSpec(ctx *deploy
|
|||
devfileImagesEnv := util.GetEnvByRegExp("^.*devfile_registry_image.*$")
|
||||
|
||||
// If there is a devfile registry deployed by operator
|
||||
if ctx.CheCluster.IsInternalClusterSVCNamesEnabled() && !ctx.CheCluster.Spec.Server.ExternalDevfileRegistry {
|
||||
if !ctx.CheCluster.Spec.Server.ExternalDevfileRegistry {
|
||||
devfileImagesEnv = append(devfileImagesEnv,
|
||||
corev1.EnvVar{
|
||||
Name: "CHE_DEVFILE_REGISTRY_INTERNAL_URL",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import (
|
|||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
@ -38,7 +37,6 @@ func TestDevfileRegistryReconcile(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, &corev1.Service{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, &routev1.Route{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, &corev1.ConfigMap{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, &appsv1.Deployment{}))
|
||||
assert.NotEmpty(t, ctx.CheCluster.Status.DevfileRegistryURL)
|
||||
|
|
@ -72,7 +70,7 @@ func TestShouldSetUpCorrectlyDevfileRegistryURL(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expectedDevfileRegistryURL: "http://devfile-registry-eclipse-che./",
|
||||
expectedDevfileRegistryURL: "https:///devfile-registry",
|
||||
},
|
||||
{
|
||||
name: "Test Status.DevfileRegistryURL #2",
|
||||
|
|
@ -95,7 +93,7 @@ func TestShouldSetUpCorrectlyDevfileRegistryURL(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
expectedDevfileRegistryURL: "http://devfile-registry-eclipse-che./",
|
||||
expectedDevfileRegistryURL: "https:///devfile-registry",
|
||||
},
|
||||
{
|
||||
name: "Test Status.DevfileRegistryURL #2",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import (
|
|||
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"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"
|
||||
|
|
@ -32,11 +31,9 @@ const (
|
|||
func Expose(
|
||||
deployContext *deploy.DeployContext,
|
||||
componentName string,
|
||||
routeCustomSettings orgv1.RouteCustomSettings,
|
||||
ingressCustomSettings orgv1.IngressCustomSettings,
|
||||
gatewayConfig *gateway.TraefikConfig) (endpointUrl string, done bool, err error) {
|
||||
//the host and path are empty and will be evaluated for the specified component + path
|
||||
return ExposeWithHostPath(deployContext, componentName, "", "", routeCustomSettings, ingressCustomSettings, gatewayConfig)
|
||||
return ExposeWithHostPath(deployContext, componentName, "", "", gatewayConfig)
|
||||
}
|
||||
|
||||
//Expose exposes the specified component on the specified host and domain.
|
||||
|
|
@ -47,78 +44,24 @@ func ExposeWithHostPath(
|
|||
component string,
|
||||
host string,
|
||||
path string,
|
||||
routeCustomSettings orgv1.RouteCustomSettings,
|
||||
ingressCustomSettings orgv1.IngressCustomSettings,
|
||||
gatewayConfig *gateway.TraefikConfig) (endpointUrl string, done bool, err error) {
|
||||
|
||||
exposureStrategy := util.GetServerExposureStrategy(deployContext.CheCluster)
|
||||
|
||||
if path != "" && !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
singleHostExposureType := deploy.GetSingleHostExposureType(deployContext.CheCluster)
|
||||
useGateway := exposureStrategy == "single-host" && (util.IsOpenShift || singleHostExposureType == deploy.GatewaySingleHostExposureType)
|
||||
if !util.IsOpenShift {
|
||||
if useGateway {
|
||||
return exposeWithGateway(deployContext, gatewayConfig, component, path, func() {
|
||||
if _, err = deploy.DeleteNamespacedObject(deployContext, component, &networking.Ingress{}); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
endpointUrl, done, err = deploy.SyncIngressToCluster(deployContext, component, host, path, component, 8080, ingressCustomSettings, component)
|
||||
if !done {
|
||||
logrus.Infof("Waiting on ingress '%s' to be ready", component)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
return "", false, err
|
||||
}
|
||||
if err := gateway.DeleteGatewayRouteConfig(component, deployContext); !util.IsTestMode() && err != nil {
|
||||
return exposeWithGateway(deployContext, gatewayConfig, component, path, func() {
|
||||
if _, err = deploy.DeleteNamespacedObject(deployContext, component, &networking.Ingress{}); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
return endpointUrl, true, nil
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if useGateway {
|
||||
return exposeWithGateway(deployContext, gatewayConfig, component, path, func() {
|
||||
if _, err := deploy.DeleteNamespacedObject(deployContext, component, &routev1.Route{}); !util.IsTestMode() && err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// the empty string for a host is intentional here - we let OpenShift decide on the hostname
|
||||
done, err := deploy.SyncRouteToCluster(deployContext, component, host, path, component, 8080, routeCustomSettings, component)
|
||||
if !done {
|
||||
logrus.Infof("Waiting on route '%s' to be ready", component)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
route := &routev1.Route{}
|
||||
exists, err := deploy.GetNamespacedObject(deployContext, component, route)
|
||||
if !exists {
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
if err := gateway.DeleteGatewayRouteConfig(component, deployContext); !util.IsTestMode() && err != nil {
|
||||
return exposeWithGateway(deployContext, gatewayConfig, component, path, func() {
|
||||
if _, err := deploy.DeleteNamespacedObject(deployContext, component, &routev1.Route{}); !util.IsTestMode() && err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
// Keycloak needs special rule in multihost. It's exposed on / which redirects to /auth
|
||||
// clients which does not support redirects needs /auth be explicitely set
|
||||
if path == "" && component == deploy.IdentityProviderName {
|
||||
path = "/auth"
|
||||
}
|
||||
return route.Spec.Host + path, true, nil
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,11 +86,7 @@ func exposeWithGateway(deployContext *deploy.DeployContext,
|
|||
cleanUpRouting()
|
||||
|
||||
if path == "" {
|
||||
if component == deploy.IdentityProviderName {
|
||||
path = "/auth"
|
||||
} else {
|
||||
path = "/" + component
|
||||
}
|
||||
path = "/" + component
|
||||
}
|
||||
return deployContext.CheCluster.Spec.Server.CheHost + path, true, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,13 +84,7 @@ func (p *GatewayReconciler) Finalize(ctx *deploy.DeployContext) bool {
|
|||
|
||||
// SyncGatewayToCluster installs or deletes the gateway based on the custom resource configuration
|
||||
func SyncGatewayToCluster(deployContext *deploy.DeployContext) error {
|
||||
if (util.GetServerExposureStrategy(deployContext.CheCluster) == "single-host" &&
|
||||
deploy.GetSingleHostExposureType(deployContext.CheCluster) == deploy.GatewaySingleHostExposureType) ||
|
||||
deployContext.CheCluster.Spec.DevWorkspace.Enable {
|
||||
return syncAll(deployContext)
|
||||
}
|
||||
|
||||
return deleteAll(deployContext)
|
||||
return syncAll(deployContext)
|
||||
}
|
||||
|
||||
func syncAll(deployContext *deploy.DeployContext) error {
|
||||
|
|
@ -110,33 +104,31 @@ func syncAll(deployContext *deploy.DeployContext) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if deployContext.CheCluster.IsNativeUserModeEnabled() {
|
||||
if oauthSecret, err := getGatewaySecretSpec(deployContext); err == nil {
|
||||
if _, err := deploy.Sync(deployContext, oauthSecret, secretDiffOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
oauthProxyConfig := getGatewayOauthProxyConfigSpec(instance, string(oauthSecret.Data["cookie_secret"]))
|
||||
if _, err := deploy.Sync(deployContext, &oauthProxyConfig, configMapDiffOpts); err != nil {
|
||||
if oauthSecret, err := getGatewaySecretSpec(deployContext); err == nil {
|
||||
if _, err := deploy.Sync(deployContext, oauthSecret, secretDiffOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
oauthProxyConfig := getGatewayOauthProxyConfigSpec(instance, string(oauthSecret.Data["cookie_secret"]))
|
||||
if _, err := deploy.Sync(deployContext, &oauthProxyConfig, configMapDiffOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
kubeRbacProxyConfig := getGatewayKubeRbacProxyConfigSpec(instance)
|
||||
if _, err := deploy.Sync(deployContext, &kubeRbacProxyConfig, configMapDiffOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if util.IsOpenShift {
|
||||
if headerRewritePluginConfig, err := getGatewayHeaderRewritePluginConfigSpec(instance); err == nil {
|
||||
if _, err := deploy.Sync(deployContext, headerRewritePluginConfig, configMapDiffOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
kubeRbacProxyConfig := getGatewayKubeRbacProxyConfigSpec(instance)
|
||||
if _, err := deploy.Sync(deployContext, &kubeRbacProxyConfig, configMapDiffOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if util.IsOpenShift {
|
||||
if headerRewritePluginConfig, err := getGatewayHeaderRewritePluginConfigSpec(instance); err == nil {
|
||||
if _, err := deploy.Sync(deployContext, headerRewritePluginConfig, configMapDiffOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traefikConfig := getGatewayTraefikConfigSpec(instance)
|
||||
|
|
@ -196,73 +188,6 @@ func generateOauthSecretSpec(deployContext *deploy.DeployContext) *corev1.Secret
|
|||
}
|
||||
}
|
||||
|
||||
func deleteAll(deployContext *deploy.DeployContext) error {
|
||||
instance := deployContext.CheCluster
|
||||
clusterAPI := deployContext.ClusterAPI
|
||||
|
||||
deployment := appsv1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: GatewayServiceName,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
}
|
||||
if err := delete(clusterAPI, &deployment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverConfig := corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: GatewayConfigMapNamePrefix + serverComponentName,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
}
|
||||
if err := delete(clusterAPI, &serverConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
traefikConfig := corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-gateway-config",
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
}
|
||||
if err := delete(clusterAPI, &traefikConfig); err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
roleBinding := rbac.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: GatewayServiceName,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
}
|
||||
if err := delete(clusterAPI, &roleBinding); err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
role := rbac.Role{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: GatewayServiceName,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
}
|
||||
if err := delete(clusterAPI, &role); err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sa := corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: GatewayServiceName,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
}
|
||||
if err := delete(clusterAPI, &sa); err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func delete(clusterAPI deploy.ClusterAPI, obj metav1.Object) error {
|
||||
key := client.ObjectKey{Name: obj.GetName(), Namespace: obj.GetNamespace()}
|
||||
ro := obj.(client.Object)
|
||||
|
|
@ -298,7 +223,7 @@ func getGatewayServerConfigSpec(deployContext *deploy.DeployContext) (corev1.Con
|
|||
"http://"+deploy.CheServiceName+":8080",
|
||||
[]string{})
|
||||
|
||||
if util.IsOpenShift && deployContext.CheCluster.IsNativeUserModeEnabled() {
|
||||
if util.IsOpenShift {
|
||||
cfg.AddAuthHeaderRewrite(serverComponentName)
|
||||
// native user mode is currently only available on OpenShift but let's be defensive here so that
|
||||
// this doesn't break once we enable it on Kubernetes, too. Token check will have to work
|
||||
|
|
@ -439,10 +364,7 @@ func getGatewayHeaderRewritePluginConfigSpec(instance *orgv1.CheCluster) (*corev
|
|||
}
|
||||
|
||||
func getGatewayTraefikConfigSpec(instance *orgv1.CheCluster) corev1.ConfigMap {
|
||||
traefikPort := GatewayServicePort
|
||||
if instance.IsNativeUserModeEnabled() {
|
||||
traefikPort = 8081
|
||||
}
|
||||
traefikPort := 8081
|
||||
data := fmt.Sprintf(`
|
||||
entrypoints:
|
||||
http:
|
||||
|
|
@ -463,7 +385,7 @@ providers:
|
|||
log:
|
||||
level: "INFO"`, traefikPort)
|
||||
|
||||
if util.IsOpenShift && instance.IsNativeUserModeEnabled() {
|
||||
if util.IsOpenShift {
|
||||
data += `
|
||||
experimental:
|
||||
localPlugins:
|
||||
|
|
@ -590,11 +512,9 @@ func getContainersSpec(instance *orgv1.CheCluster) []corev1.Container {
|
|||
},
|
||||
}
|
||||
|
||||
if instance.IsNativeUserModeEnabled() {
|
||||
containers = append(containers,
|
||||
getOauthProxyContainerSpec(instance),
|
||||
getKubeRbacProxyContainerSpec(instance))
|
||||
}
|
||||
containers = append(containers,
|
||||
getOauthProxyContainerSpec(instance),
|
||||
getKubeRbacProxyContainerSpec(instance))
|
||||
|
||||
return containers
|
||||
}
|
||||
|
|
@ -610,7 +530,7 @@ func getTraefikContainerVolumeMounts(instance *orgv1.CheCluster) []corev1.Volume
|
|||
MountPath: "/dynamic-config",
|
||||
},
|
||||
}
|
||||
if util.IsOpenShift && instance.IsNativeUserModeEnabled() {
|
||||
if util.IsOpenShift {
|
||||
mounts = append(mounts, corev1.VolumeMount{
|
||||
Name: "header-rewrite-traefik-plugin",
|
||||
MountPath: "/plugins-local/src/github.com/che-incubator/header-rewrite-traefik-plugin",
|
||||
|
|
@ -640,23 +560,21 @@ func getVolumesSpec(instance *orgv1.CheCluster) []corev1.Volume {
|
|||
},
|
||||
}
|
||||
|
||||
if instance.IsNativeUserModeEnabled() {
|
||||
volumes = append(volumes,
|
||||
getOauthProxyConfigVolume(),
|
||||
getKubeRbacProxyConfigVolume())
|
||||
volumes = append(volumes,
|
||||
getOauthProxyConfigVolume(),
|
||||
getKubeRbacProxyConfigVolume())
|
||||
|
||||
if util.IsOpenShift {
|
||||
volumes = append(volumes, corev1.Volume{
|
||||
Name: "header-rewrite-traefik-plugin",
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
ConfigMap: &corev1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "che-gateway-config-header-rewrite-traefik-plugin",
|
||||
},
|
||||
if util.IsOpenShift {
|
||||
volumes = append(volumes, corev1.Volume{
|
||||
Name: "header-rewrite-traefik-plugin",
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
ConfigMap: &corev1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "che-gateway-config-header-rewrite-traefik-plugin",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return volumes
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
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/client-go/kubernetes/scheme"
|
||||
|
|
@ -42,11 +41,6 @@ func TestSyncAllToCluster(t *testing.T) {
|
|||
Namespace: "eclipse-che",
|
||||
Name: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "single-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
|
|
@ -66,8 +60,8 @@ func TestSyncAllToCluster(t *testing.T) {
|
|||
t.Fatalf("Failed to get deployment: %v", err)
|
||||
}
|
||||
|
||||
assert.Lenf(t, deployment.Spec.Template.Spec.Containers, 2,
|
||||
"With classic multi-user, there should be 2 containers in the gateway, traefik and configbump. But it has '%d' containers.", len(deployment.Spec.Template.Spec.Containers))
|
||||
assert.Lenf(t, deployment.Spec.Template.Spec.Containers, 4,
|
||||
"There should be 4 containers in the gateway. But it has '%d' containers.", len(deployment.Spec.Template.Spec.Containers))
|
||||
for _, c := range deployment.Spec.Template.Spec.Containers {
|
||||
assert.NotNil(t, c.Resources, "container '%s' has not set resources", c.Name)
|
||||
}
|
||||
|
|
@ -84,21 +78,12 @@ func TestNativeUserGateway(t *testing.T) {
|
|||
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
corev1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
|
||||
nativeUserMode := true
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
Name: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
NativeUserMode: &nativeUserMode,
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "single-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
|
|
@ -138,49 +123,6 @@ func TestNativeUserGateway(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNoGatewayForMultiHost(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",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
NonCachingClient: cli,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
}
|
||||
|
||||
err := SyncGatewayToCluster(deployContext)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to sync Gateway: %v", err)
|
||||
}
|
||||
|
||||
deployment := &appsv1.Deployment{}
|
||||
err = cli.Get(context.TODO(), types.NamespacedName{Name: GatewayServiceName, Namespace: "eclipse-che"}, deployment)
|
||||
if err == nil {
|
||||
t.Fatalf("Failed to get deployment: %v", err)
|
||||
} else {
|
||||
if v, ok := err.(errors.APIStatus); ok {
|
||||
if v.Status().Code != 404 {
|
||||
t.Fatalf("Deployment should not be found, thus code 404, but got '%d'", v.Status().Code)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("Wrong error returned.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomCookieSecret(t *testing.T) {
|
||||
secret := generateRandomCookieSecret()
|
||||
if len(secret) != 24 {
|
||||
|
|
@ -194,6 +136,9 @@ func TestRandomCookieSecret(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestOauthProxyConfigUnauthorizedPaths(t *testing.T) {
|
||||
util.IsOpenShift = true
|
||||
util.IsOpenShift4 = true
|
||||
|
||||
t.Run("no skip auth", func(t *testing.T) {
|
||||
configmap := getGatewayOauthProxyConfigSpec(&orgv1.CheCluster{
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
|
|
@ -202,7 +147,7 @@ func TestOauthProxyConfigUnauthorizedPaths(t *testing.T) {
|
|||
ExternalPluginRegistry: true,
|
||||
}}}, "blabol")
|
||||
config := configmap.Data["oauth-proxy.cfg"]
|
||||
if strings.Contains(config, "skip_auth_regex") {
|
||||
if !strings.Contains(config, "skip_auth_regex = \"/healthz$\"") {
|
||||
t.Errorf("oauth config shold not contain any skip auth when both registries are external")
|
||||
}
|
||||
})
|
||||
|
|
@ -216,7 +161,7 @@ func TestOauthProxyConfigUnauthorizedPaths(t *testing.T) {
|
|||
ExternalPluginRegistry: true,
|
||||
}}}, "blabol")
|
||||
config := configmap.Data["oauth-proxy.cfg"]
|
||||
if !strings.Contains(config, "skip_auth_regex = \"^/devfile-registry\"") {
|
||||
if !strings.Contains(config, "skip_auth_regex = \"^/devfile-registry|/healthz$\"") {
|
||||
t.Error("oauth config should skip auth for devfile registry", config)
|
||||
}
|
||||
})
|
||||
|
|
@ -229,7 +174,7 @@ func TestOauthProxyConfigUnauthorizedPaths(t *testing.T) {
|
|||
ExternalPluginRegistry: false,
|
||||
}}}, "blabol")
|
||||
config := configmap.Data["oauth-proxy.cfg"]
|
||||
if !strings.Contains(config, "skip_auth_regex = \"^/plugin-registry\"") {
|
||||
if !strings.Contains(config, "skip_auth_regex = \"^/plugin-registry|/healthz$\"") {
|
||||
t.Error("oauth config should skip auth for plugin registry", config)
|
||||
}
|
||||
})
|
||||
|
|
@ -242,17 +187,14 @@ func TestOauthProxyConfigUnauthorizedPaths(t *testing.T) {
|
|||
ExternalPluginRegistry: false,
|
||||
}}}, "blabol")
|
||||
config := configmap.Data["oauth-proxy.cfg"]
|
||||
if !strings.Contains(config, "skip_auth_regex = \"^/plugin-registry|^/devfile-registry\"") {
|
||||
if !strings.Contains(config, "skip_auth_regex = \"^/plugin-registry|^/devfile-registry|/healthz$\"") {
|
||||
t.Error("oauth config should skip auth for plugin and devfile registry.", config)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("skip '/healthz' path", func(t *testing.T) {
|
||||
configmap := getGatewayOauthProxyConfigSpec(&orgv1.CheCluster{
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
NativeUserMode: util.NewBoolPointer(true),
|
||||
}}}, "blabol")
|
||||
Spec: orgv1.CheClusterSpec{}}, "blabol")
|
||||
config := configmap.Data["oauth-proxy.cfg"]
|
||||
assert.Contains(t, config, "/healthz$")
|
||||
})
|
||||
|
|
@ -264,13 +206,7 @@ func TestTokenValidityCheckOnOpenShiftNativeUser(t *testing.T) {
|
|||
corev1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
|
||||
cm, err := getGatewayServerConfigSpec(&deploy.DeployContext{
|
||||
CheCluster: &orgv1.CheCluster{
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
NativeUserMode: util.NewBoolPointer(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
CheCluster: &orgv1.CheCluster{},
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -116,9 +116,7 @@ func skipAuthConfig(instance *orgv1.CheCluster) string {
|
|||
if !instance.Spec.Server.ExternalDevfileRegistry {
|
||||
skipAuthPaths = append(skipAuthPaths, "^/"+deploy.DevfileRegistryName)
|
||||
}
|
||||
if instance.IsNativeUserModeEnabled() {
|
||||
skipAuthPaths = append(skipAuthPaths, "/healthz$")
|
||||
}
|
||||
skipAuthPaths = append(skipAuthPaths, "/healthz$")
|
||||
if len(skipAuthPaths) > 0 {
|
||||
propName := "skip_auth_routes"
|
||||
if util.IsOpenShift {
|
||||
|
|
|
|||
|
|
@ -1,864 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 identityprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/postgres"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/tls"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/sirupsen/logrus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
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"
|
||||
)
|
||||
|
||||
const (
|
||||
selectSslRequiredCommand = "OUT=$(psql keycloak -tAc \"SELECT 1 FROM REALM WHERE id = 'master'\"); " +
|
||||
"if [ $OUT -eq 1 ]; then psql keycloak -tAc \"SELECT ssl_required FROM REALM WHERE id = 'master'\"; fi"
|
||||
updateSslRequiredCommand = "psql keycloak -c \"update REALM set ssl_required='NONE' where id = 'master'\""
|
||||
)
|
||||
|
||||
var (
|
||||
trustpass = util.GeneratePasswd(12)
|
||||
keycloakCustomDiffOpts = cmp.Options{
|
||||
deploy.DefaultDeploymentDiffOpts,
|
||||
cmp.Comparer(func(x, y metav1.ObjectMeta) bool {
|
||||
return x.Annotations["che.self-signed-certificate.version"] == y.Annotations["che.self-signed-certificate.version"] &&
|
||||
x.Annotations["che.openshift-api-crt.version"] == y.Annotations["che.openshift-api-crt.version"] &&
|
||||
x.Annotations["che.keycloak-ssl-required-updated"] == y.Annotations["che.keycloak-ssl-required-updated"]
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
func SyncKeycloakDeploymentToCluster(deployContext *deploy.DeployContext) (bool, error) {
|
||||
actual := &appsv1.Deployment{}
|
||||
exists, err := deploy.GetNamespacedObject(deployContext, deploy.IdentityProviderName, actual)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
actual = nil
|
||||
}
|
||||
|
||||
specDeployment, err := GetSpecKeycloakDeployment(deployContext, actual)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return deploy.SyncDeploymentSpecToCluster(deployContext, specDeployment, deploy.DefaultDeploymentDiffOpts)
|
||||
}
|
||||
|
||||
func GetSpecKeycloakDeployment(
|
||||
deployContext *deploy.DeployContext,
|
||||
clusterDeployment *appsv1.Deployment) (*appsv1.Deployment, error) {
|
||||
optionalEnv := true
|
||||
labels, labelSelector := deploy.GetLabelsAndSelector(deployContext.CheCluster, deploy.IdentityProviderName)
|
||||
cheFlavor := deploy.DefaultCheFlavor(deployContext.CheCluster)
|
||||
keycloakImage := util.GetValue(deployContext.CheCluster.Spec.Auth.IdentityProviderImage, deploy.DefaultKeycloakImage(deployContext.CheCluster))
|
||||
pullPolicy := corev1.PullPolicy(util.GetValue(string(deployContext.CheCluster.Spec.Auth.IdentityProviderImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(keycloakImage)))
|
||||
jbossDir := "/opt/eap"
|
||||
if cheFlavor == "che" {
|
||||
// writable dir in the upstream Keycloak image
|
||||
jbossDir = "/scripts"
|
||||
}
|
||||
jbossCli := "/opt/jboss/keycloak/bin/jboss-cli.sh"
|
||||
if cheFlavor == "codeready" {
|
||||
jbossCli = "/opt/eap/bin/jboss-cli.sh"
|
||||
}
|
||||
|
||||
if clusterDeployment != nil {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmResourceVersions := tls.GetAdditionalCACertsConfigMapVersion(deployContext)
|
||||
terminationGracePeriodSeconds := int64(30)
|
||||
cheCertSecretVersion := getSecretResourceVersion("self-signed-certificate", deployContext.CheCluster.Namespace, deployContext.ClusterAPI)
|
||||
openshiftApiCertSecretVersion := getSecretResourceVersion("openshift-api-crt", deployContext.CheCluster.Namespace, deployContext.ClusterAPI)
|
||||
|
||||
// holds bash functions that should be available when run init commands in shell
|
||||
bashFunctions := ""
|
||||
|
||||
// add various certificates to Java trust store so that Keycloak can connect to OpenShift API
|
||||
// certificate that OpenShift router uses (for 4.0 only)
|
||||
addRouterCrt := "if [ ! -z \"${CHE_SELF__SIGNED__CERT}\" ]; then echo \"${CHE_SELF__SIGNED__CERT}\" > " + jbossDir + "/che.crt && " +
|
||||
"keytool -importcert -alias ROUTERCRT" +
|
||||
" -keystore " + jbossDir + "/openshift.jks" +
|
||||
" -file " + jbossDir + "/che.crt -storepass " + trustpass + " -noprompt; fi"
|
||||
// certificate retrieved from http call to OpenShift API endpoint
|
||||
addOpenShiftAPICrt := "if [ ! -z \"${OPENSHIFT_SELF__SIGNED__CERT}\" ]; then echo \"${OPENSHIFT_SELF__SIGNED__CERT}\" > " + jbossDir + "/openshift.crt && " +
|
||||
"keytool -importcert -alias OPENSHIFTAPI" +
|
||||
" -keystore " + jbossDir + "/openshift.jks" +
|
||||
" -file " + jbossDir + "/openshift.crt -storepass " + trustpass + " -noprompt; fi"
|
||||
// certificate mounted into container /var/run/secrets
|
||||
addMountedCrt := " keytool -importcert -alias MOUNTEDCRT" +
|
||||
" -keystore " + jbossDir + "/openshift.jks" +
|
||||
" -file /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -storepass " + trustpass + " -noprompt"
|
||||
addMountedServiceCrt := "if [ -f /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt ]; then " +
|
||||
"keytool -importcert -alias MOUNTEDSERVICECRT" +
|
||||
" -keystore " + jbossDir + "/openshift.jks" +
|
||||
" -file /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt -storepass " + trustpass + " -noprompt; fi"
|
||||
importJavaCacerts := "keytool -importkeystore -srckeystore /etc/pki/ca-trust/extracted/java/cacerts" +
|
||||
" -destkeystore " + jbossDir + "/openshift.jks" +
|
||||
" -srcstorepass changeit -deststorepass " + trustpass
|
||||
|
||||
customPublicCertsDir := "/public-certs"
|
||||
customPublicCertsVolumeSource := corev1.VolumeSource{}
|
||||
customPublicCertsVolumeSource = corev1.VolumeSource{
|
||||
ConfigMap: &corev1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: tls.CheAllCACertsConfigMapName,
|
||||
},
|
||||
},
|
||||
}
|
||||
customPublicCertsVolume := corev1.Volume{
|
||||
Name: "che-public-certs",
|
||||
VolumeSource: customPublicCertsVolumeSource,
|
||||
}
|
||||
customPublicCertsVolumeMount := corev1.VolumeMount{
|
||||
Name: "che-public-certs",
|
||||
MountPath: customPublicCertsDir,
|
||||
}
|
||||
addCustomPublicCertsCommand := "if [[ -d \"" + customPublicCertsDir + "\" && -n \"$(find " + customPublicCertsDir + " -type f)\" ]]; then " +
|
||||
"for certfile in " + customPublicCertsDir + "/* ; do " +
|
||||
"jks_import_ca_bundle $certfile " + jbossDir + "/openshift.jks " + trustpass + " ; " +
|
||||
"done; fi"
|
||||
|
||||
bashFunctions += getImportCABundleScript()
|
||||
addCertToTrustStoreCommand := addRouterCrt + " && " + addOpenShiftAPICrt + " && " + addMountedCrt + " && " + addMountedServiceCrt + " && " + importJavaCacerts + " && " + addCustomPublicCertsCommand
|
||||
|
||||
// upstream Keycloak has a bit different mechanism of adding jks
|
||||
changeConfigCommand := "echo Installing certificates into Keycloak && " +
|
||||
"echo -e \"embed-server --server-config=standalone.xml --std-out=echo \n" +
|
||||
"/subsystem=keycloak-server/spi=truststore/:add \n" +
|
||||
"/subsystem=keycloak-server/spi=truststore/provider=file/:add(properties={file => " +
|
||||
"\"" + jbossDir + "/openshift.jks\", password => \"" + trustpass + "\", disabled => \"false\" },enabled=true) \n" +
|
||||
"stop-embedded-server\" > /scripts/add_openshift_certificate.cli && " +
|
||||
"/opt/jboss/keycloak/bin/jboss-cli.sh --file=/scripts/add_openshift_certificate.cli"
|
||||
|
||||
addProxyCliCommand := ""
|
||||
applyProxyCliCommand := ""
|
||||
proxyEnvVars := []corev1.EnvVar{}
|
||||
|
||||
if deployContext.Proxy.HttpProxy != "" {
|
||||
proxyEnvVars = []corev1.EnvVar{
|
||||
{
|
||||
Name: "HTTP_PROXY",
|
||||
Value: deployContext.Proxy.HttpProxy,
|
||||
},
|
||||
{
|
||||
Name: "HTTPS_PROXY",
|
||||
Value: deployContext.Proxy.HttpsProxy,
|
||||
},
|
||||
{
|
||||
Name: "NO_PROXY",
|
||||
Value: deployContext.Proxy.NoProxy,
|
||||
},
|
||||
}
|
||||
|
||||
quotedNoProxy := ""
|
||||
for _, noProxyHost := range strings.Split(deployContext.Proxy.NoProxy, ",") {
|
||||
if len(quotedNoProxy) != 0 {
|
||||
quotedNoProxy += ","
|
||||
}
|
||||
|
||||
var noProxyEntry string
|
||||
if strings.HasPrefix(noProxyHost, ".") {
|
||||
noProxyEntry = ".*" + strings.ReplaceAll(regexp.QuoteMeta(noProxyHost), "\\", "\\\\\\")
|
||||
} else if strings.HasPrefix(noProxyHost, "*.") {
|
||||
noProxyEntry = strings.TrimPrefix(noProxyHost, "*")
|
||||
noProxyEntry = ".*" + strings.ReplaceAll(regexp.QuoteMeta(noProxyEntry), "\\", "\\\\\\")
|
||||
} else {
|
||||
noProxyEntry = strings.ReplaceAll(regexp.QuoteMeta(noProxyHost), "\\", "\\\\\\")
|
||||
}
|
||||
quotedNoProxy += "\"" + noProxyEntry + ";NO_PROXY\""
|
||||
}
|
||||
|
||||
serverConfig := "standalone.xml"
|
||||
if cheFlavor == "codeready" {
|
||||
serverConfig = "standalone-openshift.xml"
|
||||
}
|
||||
addProxyCliCommand = " && echo Configuring Proxy && " +
|
||||
"echo -e 'embed-server --server-config=" + serverConfig + " --std-out=echo \n" +
|
||||
"/subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:write-attribute(name=properties.proxy-mappings,value=[" + quotedNoProxy + ",\".*;" + deployContext.Proxy.HttpProxy + "\"]) \n" +
|
||||
"stop-embedded-server' > " + jbossDir + "/setup-http-proxy.cli"
|
||||
|
||||
applyProxyCliCommand = " && " + jbossCli + " --file=" + jbossDir + "/setup-http-proxy.cli"
|
||||
if cheFlavor == "codeready" {
|
||||
applyProxyCliCommand = " && mkdir -p " + jbossDir + "/extensions && echo '#!/bin/bash\n" +
|
||||
"" + jbossDir + "/bin/jboss-cli.sh --file=" + jbossDir + "/setup-http-proxy.cli' > " + jbossDir + "/extensions/postconfigure.sh && " +
|
||||
"chmod a+x " + jbossDir + "/extensions/postconfigure.sh "
|
||||
}
|
||||
}
|
||||
|
||||
keycloakEnv := []corev1.EnvVar{
|
||||
{
|
||||
Name: "CM_REVISION",
|
||||
Value: cmResourceVersions,
|
||||
},
|
||||
{
|
||||
Name: "PROXY_ADDRESS_FORWARDING",
|
||||
Value: "true",
|
||||
},
|
||||
{
|
||||
Name: "DB_VENDOR",
|
||||
Value: "POSTGRES",
|
||||
},
|
||||
{
|
||||
Name: "DB_USERNAME",
|
||||
Value: "keycloak",
|
||||
},
|
||||
{
|
||||
Name: "DB_ADDR",
|
||||
Value: util.GetValue(deployContext.CheCluster.Spec.Database.ChePostgresHostName, deploy.DefaultChePostgresHostName),
|
||||
},
|
||||
{
|
||||
Name: "DB_DATABASE",
|
||||
Value: "keycloak",
|
||||
},
|
||||
{
|
||||
Name: "POSTGRES_PORT_5432_TCP_ADDR",
|
||||
Value: util.GetValue(deployContext.CheCluster.Spec.Database.ChePostgresHostName, deploy.DefaultChePostgresHostName),
|
||||
},
|
||||
{
|
||||
Name: "POSTGRES_PORT_5432_TCP_PORT",
|
||||
Value: util.GetValue(deployContext.CheCluster.Spec.Database.ChePostgresPort, deploy.DefaultChePostgresPort),
|
||||
},
|
||||
{
|
||||
Name: "POSTGRES_PORT",
|
||||
Value: util.GetValue(deployContext.CheCluster.Spec.Database.ChePostgresPort, deploy.DefaultChePostgresPort),
|
||||
},
|
||||
{
|
||||
Name: "POSTGRES_USER",
|
||||
Value: "keycloak",
|
||||
},
|
||||
{
|
||||
Name: "SSO_TRUSTSTORE",
|
||||
Value: "openshift.jks",
|
||||
},
|
||||
{
|
||||
Name: "SSO_TRUSTSTORE_DIR",
|
||||
Value: jbossDir,
|
||||
},
|
||||
{
|
||||
Name: "SSO_TRUSTSTORE_PASSWORD",
|
||||
Value: trustpass,
|
||||
},
|
||||
{
|
||||
Name: "CHE_SELF__SIGNED__CERT",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "ca.crt",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: deploy.CheTLSSelfSignedCertificateSecretName,
|
||||
},
|
||||
Optional: &optionalEnv,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "OPENSHIFT_SELF__SIGNED__CERT",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "ca.crt",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "openshift-api-crt",
|
||||
},
|
||||
Optional: &optionalEnv,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
identityProviderPostgresSecret := deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresSecret
|
||||
if len(identityProviderPostgresSecret) > 0 {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "DB_PASSWORD",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "password",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderPostgresSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "DB_PASSWORD",
|
||||
Value: deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresPassword,
|
||||
})
|
||||
}
|
||||
|
||||
identityProviderSecret := deployContext.CheCluster.Spec.Auth.IdentityProviderSecret
|
||||
if len(identityProviderSecret) > 0 {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "KEYCLOAK_PASSWORD",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "password",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
corev1.EnvVar{
|
||||
Name: "KEYCLOAK_USER",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "user",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "KEYCLOAK_PASSWORD",
|
||||
Value: deployContext.CheCluster.Spec.Auth.IdentityProviderPassword,
|
||||
},
|
||||
corev1.EnvVar{
|
||||
Name: "KEYCLOAK_USER",
|
||||
Value: deployContext.CheCluster.Spec.Auth.IdentityProviderAdminUserName,
|
||||
})
|
||||
}
|
||||
|
||||
if cheFlavor == "codeready" {
|
||||
keycloakEnv = []corev1.EnvVar{
|
||||
{
|
||||
Name: "CM_REVISION",
|
||||
Value: cmResourceVersions,
|
||||
},
|
||||
{
|
||||
Name: "PROXY_ADDRESS_FORWARDING",
|
||||
Value: "true",
|
||||
},
|
||||
{
|
||||
Name: "DB_SERVICE_PREFIX_MAPPING",
|
||||
Value: "keycloak-postgresql=DB",
|
||||
},
|
||||
{
|
||||
Name: "KEYCLOAK_POSTGRESQL_SERVICE_HOST",
|
||||
Value: util.GetValue(deployContext.CheCluster.Spec.Database.ChePostgresHostName, deploy.DefaultChePostgresHostName),
|
||||
},
|
||||
{
|
||||
Name: "KEYCLOAK_POSTGRESQL_SERVICE_PORT",
|
||||
Value: util.GetValue(deployContext.CheCluster.Spec.Database.ChePostgresPort, deploy.DefaultChePostgresPort),
|
||||
},
|
||||
{
|
||||
Name: "DB_DATABASE",
|
||||
Value: "keycloak",
|
||||
},
|
||||
{
|
||||
Name: "DB_USERNAME",
|
||||
Value: "keycloak",
|
||||
},
|
||||
{
|
||||
Name: "DB_VENDOR",
|
||||
Value: "POSTGRES",
|
||||
},
|
||||
{
|
||||
Name: "SSO_TRUSTSTORE",
|
||||
Value: "openshift.jks",
|
||||
},
|
||||
{
|
||||
Name: "SSO_TRUSTSTORE_DIR",
|
||||
Value: jbossDir,
|
||||
},
|
||||
{
|
||||
Name: "SSO_TRUSTSTORE_PASSWORD",
|
||||
Value: trustpass,
|
||||
},
|
||||
{
|
||||
Name: "CHE_SELF__SIGNED__CERT",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "ca.crt",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: deploy.CheTLSSelfSignedCertificateSecretName,
|
||||
},
|
||||
Optional: &optionalEnv,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "OPENSHIFT_SELF__SIGNED__CERT",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "ca.crt",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "openshift-api-crt",
|
||||
},
|
||||
Optional: &optionalEnv,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
identityProviderPostgresSecret := deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresSecret
|
||||
if len(identityProviderPostgresSecret) > 0 {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "DB_PASSWORD",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "password",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderPostgresSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "DB_PASSWORD",
|
||||
Value: deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresPassword,
|
||||
})
|
||||
}
|
||||
|
||||
identityProviderSecret := deployContext.CheCluster.Spec.Auth.IdentityProviderSecret
|
||||
if len(identityProviderSecret) > 0 {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "SSO_ADMIN_PASSWORD",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "password",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
corev1.EnvVar{
|
||||
Name: "SSO_ADMIN_USERNAME",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "user",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "SSO_ADMIN_PASSWORD",
|
||||
Value: deployContext.CheCluster.Spec.Auth.IdentityProviderPassword,
|
||||
},
|
||||
corev1.EnvVar{
|
||||
Name: "SSO_ADMIN_USERNAME",
|
||||
Value: deployContext.CheCluster.Spec.Auth.IdentityProviderAdminUserName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Enable internal network for keycloak
|
||||
if deployContext.CheCluster.IsInternalClusterSVCNamesEnabled() && !deployContext.CheCluster.Spec.Auth.ExternalIdentityProvider {
|
||||
keycloakEnv = append(keycloakEnv, corev1.EnvVar{
|
||||
Name: "KEYCLOAK_FRONTEND_URL",
|
||||
Value: deployContext.CheCluster.Status.KeycloakURL,
|
||||
})
|
||||
}
|
||||
|
||||
evaluateKeycloakSystemProperties := "KEYCLOAK_SYS_PROPS=\"-Dkeycloak.profile.feature.token_exchange=enabled -Dkeycloak.profile.feature.admin_fine_grained_authz=enabled\""
|
||||
if cheFlavor == "codeready" {
|
||||
// We need to export `KEYCLOAK_SYS_PROPS` to pass them to standalone.sh via openshift-launch.sh
|
||||
evaluateKeycloakSystemProperties = "export KEYCLOAK_SYS_PROPS=\"\""
|
||||
}
|
||||
|
||||
// Evaluating keycloak.connectionsHttpClient.default system properties, see details: https://github.com/eclipse/che/issues/19653
|
||||
evaluateExpectContinueEnabled := "if [[ $KEYCLOAK_CONNECTIONS_HTTP_CLIENT_DEFAULT_EXPECT_CONTINUE_ENABLED != false ]]; then KEYCLOAK_SYS_PROPS=$KEYCLOAK_SYS_PROPS\" -Dkeycloak.connectionsHttpClient.default.expect-continue-enabled=true\"; fi"
|
||||
evaluateReuseConnections := "if [[ $KEYCLOAK_CONNECTIONS_HTTP_CLIENT_DEFAULT_REUSE_CONNECTIONS != true ]]; then KEYCLOAK_SYS_PROPS=$KEYCLOAK_SYS_PROPS\" -Dkeycloak.connectionsHttpClient.default.reuse-connections=false\"; fi"
|
||||
|
||||
command := bashFunctions + "\n" +
|
||||
addCertToTrustStoreCommand +
|
||||
addProxyCliCommand +
|
||||
applyProxyCliCommand +
|
||||
" && " + evaluateKeycloakSystemProperties +
|
||||
" && " + evaluateExpectContinueEnabled +
|
||||
" && " + evaluateReuseConnections +
|
||||
" && " + changeConfigCommand +
|
||||
" && /opt/jboss/tools/docker-entrypoint.sh -b 0.0.0.0 -c standalone.xml $KEYCLOAK_SYS_PROPS"
|
||||
|
||||
if cheFlavor == "codeready" {
|
||||
addUsernameReadonlyTheme := "baseTemplate=/opt/eap/themes/base/login/login-update-profile.ftl" +
|
||||
" && readOnlyTemplateDir=/opt/eap/themes/codeready-username-readonly/login" +
|
||||
" && readOnlyTemplate=${readOnlyTemplateDir}/login-update-profile.ftl" +
|
||||
" && if [ ! -d ${readOnlyTemplateDir} ]; then" +
|
||||
" mkdir -p ${readOnlyTemplateDir}" +
|
||||
" && cp ${baseTemplate} ${readOnlyTemplate}" +
|
||||
" && echo \"parent=rh-sso\" > ${readOnlyTemplateDir}/theme.properties" +
|
||||
" && sed -i 's|id=\"username\" name=\"username\"|id=\"username\" readonly name=\"username\"|g' ${readOnlyTemplate}; fi"
|
||||
addUsernameValidationForKeycloakTheme := "sed -i 's|id=\"username\" name=\"username\"|" +
|
||||
"id=\"username\" " +
|
||||
"pattern=\"[a-z]([-a-z0-9]{0,61}[a-z0-9])?\" " +
|
||||
"title=\"Username has to comply with the DNS naming convention. An alphanumeric (a-z, and 0-9) string, with a maximum length of 63 characters, with the '-' character allowed anywhere except the first or last character.\" " +
|
||||
"name=\"username\"|g' ${baseTemplate}"
|
||||
patchOpenshiftLaunch := "sed -i 's|standalone.sh -c standalone-openshift.xml|standalone.sh -c standalone-openshift.xml ${KEYCLOAK_SYS_PROPS}|' /opt/eap/bin/openshift-launch.sh"
|
||||
command = bashFunctions + "\n" +
|
||||
addUsernameReadonlyTheme +
|
||||
" && " + addUsernameValidationForKeycloakTheme +
|
||||
" && " + addCertToTrustStoreCommand +
|
||||
addProxyCliCommand +
|
||||
applyProxyCliCommand +
|
||||
" && " + evaluateKeycloakSystemProperties +
|
||||
" && " + evaluateExpectContinueEnabled +
|
||||
" && " + evaluateReuseConnections +
|
||||
" && " + patchOpenshiftLaunch +
|
||||
" && echo \"feature.token_exchange=enabled\nfeature.admin_fine_grained_authz=enabled\" > /opt/eap/standalone/configuration/profile.properties " +
|
||||
" && sed -i 's/WILDCARD/ANY/g' /opt/eap/bin/launch/keycloak-spi.sh && /opt/eap/bin/openshift-launch.sh -b 0.0.0.0"
|
||||
}
|
||||
|
||||
sslRequiredUpdatedForMasterRealm := isSslRequiredUpdatedForMasterRealm(deployContext)
|
||||
if sslRequiredUpdatedForMasterRealm {
|
||||
// update command to restart pod
|
||||
command = "echo \"ssl_required WAS UPDATED for master realm.\" && " + command
|
||||
}
|
||||
|
||||
ports := []corev1.ContainerPort{
|
||||
{
|
||||
Name: deploy.IdentityProviderName,
|
||||
ContainerPort: 8080,
|
||||
Protocol: "TCP",
|
||||
},
|
||||
}
|
||||
|
||||
if deployContext.CheCluster.Spec.Auth.Debug {
|
||||
ports = append(ports, corev1.ContainerPort{
|
||||
Name: "debug",
|
||||
ContainerPort: 8787,
|
||||
Protocol: "TCP",
|
||||
})
|
||||
|
||||
keycloakEnv = append(keycloakEnv, []corev1.EnvVar{
|
||||
{
|
||||
Name: "DEBUG",
|
||||
Value: "true",
|
||||
},
|
||||
{
|
||||
Name: "DEBUG_PORT",
|
||||
Value: "*:8787",
|
||||
},
|
||||
}...)
|
||||
|
||||
command += " --debug"
|
||||
}
|
||||
|
||||
args := []string{"-c", command}
|
||||
|
||||
deployment := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Deployment",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deploy.IdentityProviderName,
|
||||
Namespace: deployContext.CheCluster.Namespace,
|
||||
Labels: labels,
|
||||
Annotations: map[string]string{
|
||||
"che.self-signed-certificate.version": cheCertSecretVersion,
|
||||
"che.openshift-api-crt.version": openshiftApiCertSecretVersion,
|
||||
"che.keycloak-ssl-required-updated": strconv.FormatBool(sslRequiredUpdatedForMasterRealm),
|
||||
},
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: labelSelector},
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Volumes: []corev1.Volume{
|
||||
customPublicCertsVolume,
|
||||
},
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: deploy.IdentityProviderName,
|
||||
Image: keycloakImage,
|
||||
ImagePullPolicy: pullPolicy,
|
||||
Command: []string{
|
||||
"/bin/sh",
|
||||
},
|
||||
Args: args,
|
||||
Ports: ports,
|
||||
Resources: corev1.ResourceRequirements{
|
||||
Requests: corev1.ResourceList{
|
||||
corev1.ResourceMemory: util.GetResourceQuantity(
|
||||
deployContext.CheCluster.Spec.Auth.IdentityProviderContainerResources.Requests.Memory,
|
||||
deploy.DefaultIdentityProviderMemoryRequest),
|
||||
corev1.ResourceCPU: util.GetResourceQuantity(
|
||||
deployContext.CheCluster.Spec.Auth.IdentityProviderContainerResources.Requests.Cpu,
|
||||
deploy.DefaultIdentityProviderCpuRequest),
|
||||
},
|
||||
Limits: corev1.ResourceList{
|
||||
corev1.ResourceMemory: util.GetResourceQuantity(
|
||||
deployContext.CheCluster.Spec.Auth.IdentityProviderContainerResources.Limits.Memory,
|
||||
deploy.DefaultIdentityProviderMemoryLimit),
|
||||
corev1.ResourceCPU: util.GetResourceQuantity(
|
||||
deployContext.CheCluster.Spec.Auth.IdentityProviderContainerResources.Limits.Cpu,
|
||||
deploy.DefaultIdentityProviderCpuLimit),
|
||||
},
|
||||
},
|
||||
ReadinessProbe: &corev1.Probe{
|
||||
Handler: corev1.Handler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
Path: "auth/js/keycloak.js",
|
||||
Port: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: int32(8080),
|
||||
},
|
||||
Scheme: corev1.URISchemeHTTP,
|
||||
},
|
||||
},
|
||||
InitialDelaySeconds: 30,
|
||||
FailureThreshold: 10,
|
||||
TimeoutSeconds: 5,
|
||||
PeriodSeconds: 10,
|
||||
SuccessThreshold: 1,
|
||||
},
|
||||
LivenessProbe: &corev1.Probe{
|
||||
Handler: corev1.Handler{
|
||||
TCPSocket: &corev1.TCPSocketAction{
|
||||
Port: intstr.FromInt(8080),
|
||||
},
|
||||
},
|
||||
InitialDelaySeconds: 300,
|
||||
FailureThreshold: 10,
|
||||
TimeoutSeconds: 5,
|
||||
PeriodSeconds: 10,
|
||||
SuccessThreshold: 1,
|
||||
},
|
||||
SecurityContext: &corev1.SecurityContext{
|
||||
Capabilities: &corev1.Capabilities{
|
||||
Drop: []corev1.Capability{"ALL"},
|
||||
},
|
||||
},
|
||||
Env: keycloakEnv,
|
||||
VolumeMounts: []corev1.VolumeMount{
|
||||
customPublicCertsVolumeMount,
|
||||
},
|
||||
},
|
||||
},
|
||||
TerminationGracePeriodSeconds: &terminationGracePeriodSeconds,
|
||||
RestartPolicy: "Always",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if deploy.IsComponentReadinessInitContainersConfigured(deployContext.CheCluster) {
|
||||
if !deployContext.CheCluster.Spec.Database.ExternalDb {
|
||||
waitForPostgresInitContainer, err := postgres.GetWaitForPostgresInitContainer(deployContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers, *waitForPostgresInitContainer)
|
||||
}
|
||||
}
|
||||
|
||||
return deployment, nil
|
||||
}
|
||||
|
||||
func getSecretResourceVersion(name string, namespace string, clusterAPI deploy.ClusterAPI) string {
|
||||
secret := &corev1.Secret{}
|
||||
err := clusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, secret)
|
||||
if err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
logrus.Errorf("Failed to get %s secret: %s", name, err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return secret.ResourceVersion
|
||||
}
|
||||
|
||||
func isSslRequiredUpdatedForMasterRealm(deployContext *deploy.DeployContext) bool {
|
||||
if deployContext.CheCluster.Spec.Database.ExternalDb {
|
||||
return false
|
||||
}
|
||||
|
||||
if util.IsTestMode() {
|
||||
return false
|
||||
}
|
||||
|
||||
actual := &appsv1.Deployment{}
|
||||
exists, err := deploy.GetNamespacedObject(deployContext, deploy.IdentityProviderName, actual)
|
||||
if !exists || err != nil {
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
value, err := strconv.ParseBool(actual.ObjectMeta.Annotations["che.keycloak-ssl-required-updated"])
|
||||
if err == nil && value {
|
||||
return true
|
||||
}
|
||||
|
||||
dbValue, _ := getSslRequiredForMasterRealm(deployContext.CheCluster)
|
||||
return dbValue == "NONE"
|
||||
}
|
||||
|
||||
func getSslRequiredForMasterRealm(cr *orgv1.CheCluster) (string, error) {
|
||||
stdout, err := util.K8sclient.ExecIntoPod(
|
||||
cr,
|
||||
deploy.PostgresName,
|
||||
func(cr *orgv1.CheCluster) (string, error) {
|
||||
return selectSslRequiredCommand, nil
|
||||
},
|
||||
"")
|
||||
return strings.TrimSpace(stdout), err
|
||||
}
|
||||
|
||||
func updateSslRequiredForMasterRealm(cr *orgv1.CheCluster) error {
|
||||
_, err := util.K8sclient.ExecIntoPod(
|
||||
cr,
|
||||
deploy.PostgresName,
|
||||
func(cr *orgv1.CheCluster) (string, error) {
|
||||
return updateSslRequiredCommand, nil
|
||||
},
|
||||
"Update ssl_required to NONE")
|
||||
return err
|
||||
}
|
||||
|
||||
func ProvisionKeycloakResources(deployContext *deploy.DeployContext) error {
|
||||
if !deployContext.CheCluster.Spec.Database.ExternalDb {
|
||||
value, err := getSslRequiredForMasterRealm(deployContext.CheCluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if value != "NONE" {
|
||||
err := updateSslRequiredForMasterRealm(deployContext.CheCluster)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err := util.K8sclient.ExecIntoPod(
|
||||
deployContext.CheCluster,
|
||||
deploy.IdentityProviderName,
|
||||
GetKeycloakProvisionCommand,
|
||||
"create realm, client and user")
|
||||
return err
|
||||
}
|
||||
|
||||
// getImportCABundleScript returns string which contains bash function that imports ca-bundle into jks
|
||||
// The function has three arguments:
|
||||
// - absolute path to ca-bundle file
|
||||
// - absolute path to java keystore
|
||||
// - java keystore password
|
||||
func getImportCABundleScript() string {
|
||||
return `
|
||||
function jks_import_ca_bundle {
|
||||
CA_FILE=$1
|
||||
KEYSTORE_PATH=$2
|
||||
KEYSTORE_PASSWORD=$3
|
||||
|
||||
if [ ! -f $CA_FILE ]; then
|
||||
# CA bundle file doesn't exist, skip it
|
||||
echo "Failed to import CA certificates from ${CA_FILE}. File doesn't exist"
|
||||
return
|
||||
fi
|
||||
|
||||
bundle_name=$(basename $CA_FILE)
|
||||
certs_imported=0
|
||||
cert_index=0
|
||||
tmp_file=/tmp/cert.pem
|
||||
is_cert=false
|
||||
while IFS= read -r line; do
|
||||
if [ "$line" == "-----BEGIN CERTIFICATE-----" ]; then
|
||||
# Start copying a new certificate
|
||||
is_cert=true
|
||||
cert_index=$((cert_index+1))
|
||||
# Reset destination file and add header line
|
||||
echo $line > ${tmp_file}
|
||||
elif [ "$line" == "-----END CERTIFICATE-----" ]; then
|
||||
# End of the certificate is reached, add it to trust store
|
||||
is_cert=false
|
||||
echo $line >> ${tmp_file}
|
||||
keytool -importcert -alias "${bundle_name}_${cert_index}" -keystore $KEYSTORE_PATH -file $tmp_file -storepass $KEYSTORE_PASSWORD -noprompt && \
|
||||
certs_imported=$((certs_imported+1))
|
||||
elif [ "$is_cert" == true ]; then
|
||||
# In the middle of a certificate, copy line to target file
|
||||
echo $line >> ${tmp_file}
|
||||
fi
|
||||
done < "$CA_FILE"
|
||||
echo "Imported ${certs_imported} certificates from ${CA_FILE}"
|
||||
# Clean up
|
||||
rm -f $tmp_file
|
||||
}
|
||||
`
|
||||
}
|
||||
|
|
@ -1,330 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 identityprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeployment(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
initObjects []runtime.Object
|
||||
memoryLimit string
|
||||
memoryRequest string
|
||||
cpuLimit string
|
||||
cpuRequest string
|
||||
cheCluster *orgv1.CheCluster
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Test default limits",
|
||||
initObjects: []runtime.Object{},
|
||||
memoryLimit: deploy.DefaultIdentityProviderMemoryLimit,
|
||||
memoryRequest: deploy.DefaultIdentityProviderMemoryRequest,
|
||||
cpuLimit: deploy.DefaultIdentityProviderCpuLimit,
|
||||
cpuRequest: deploy.DefaultIdentityProviderCpuRequest,
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test custom limits",
|
||||
initObjects: []runtime.Object{},
|
||||
cpuLimit: "250m",
|
||||
cpuRequest: "150m",
|
||||
memoryLimit: "250Mi",
|
||||
memoryRequest: "150Mi",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
IdentityProviderContainerResources: orgv1.ResourcesCustomSettings{
|
||||
Limits: orgv1.Resources{
|
||||
Cpu: "250m",
|
||||
Memory: "250Mi",
|
||||
},
|
||||
Requests: orgv1.Resources{
|
||||
Cpu: "150m",
|
||||
Memory: "150Mi",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(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)
|
||||
}
|
||||
|
||||
util.CompareResources(deployment,
|
||||
util.TestExpectedResources{
|
||||
MemoryLimit: testCase.memoryLimit,
|
||||
MemoryRequest: testCase.memoryRequest,
|
||||
CpuRequest: testCase.cpuRequest,
|
||||
CpuLimit: testCase.cpuLimit,
|
||||
},
|
||||
t)
|
||||
|
||||
util.ValidateSecurityContext(deployment, 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{
|
||||
Name: "che-cluster",
|
||||
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.New(zap.WriteTo(os.Stdout), zap.UseDevMode(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))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncKeycloakDeploymentToCluster(t *testing.T) {
|
||||
orgv1.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,
|
||||
NonCachingClient: cli,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
Proxy: &deploy.Proxy{},
|
||||
}
|
||||
|
||||
// initial sync
|
||||
done, err := SyncKeycloakDeploymentToCluster(deployContext)
|
||||
if !done || err != nil {
|
||||
t.Fatalf("Failed to sync deployment: %v", err)
|
||||
}
|
||||
|
||||
actual := &appsv1.Deployment{}
|
||||
err = cli.Get(context.TODO(), types.NamespacedName{Name: deploy.IdentityProviderName, Namespace: "eclipse-che"}, actual)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to sync deployment: %v", err)
|
||||
}
|
||||
|
||||
// create certs configmap
|
||||
err = cli.Create(context.TODO(), &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "ca-certs-merged",
|
||||
Namespace: "eclipse-che",
|
||||
// Go client set up resource version 1 itself on object creation.
|
||||
// ResourceVersion: "1",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create configmap: %v", err)
|
||||
}
|
||||
|
||||
// create self-signed-certificate secret
|
||||
err = cli.Create(context.TODO(), &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "self-signed-certificate",
|
||||
Namespace: "eclipse-che",
|
||||
// Go client set up resource version 1 itself on object creation.
|
||||
// ResourceVersion: "1",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create secret: %v", err)
|
||||
}
|
||||
|
||||
caSecret := &corev1.Secret{}
|
||||
err = cli.Get(context.TODO(), types.NamespacedName{
|
||||
Name: "self-signed-certificate",
|
||||
Namespace: "eclipse-che",
|
||||
}, caSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get secret: %v", err)
|
||||
}
|
||||
// Let's really change something. Go client will increment secret resource version itself(from '1' to '2').
|
||||
caSecret.GenerateName = "test"
|
||||
|
||||
err = cli.Update(context.TODO(), caSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to update secret: %s", err.Error())
|
||||
}
|
||||
|
||||
// sync a new deployment
|
||||
_, err = SyncKeycloakDeploymentToCluster(deployContext)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to sync deployment: %v", err)
|
||||
}
|
||||
|
||||
// sync twice to be sure update done correctly
|
||||
done, err = SyncKeycloakDeploymentToCluster(deployContext)
|
||||
if !done || err != nil {
|
||||
t.Fatalf("Failed to sync deployment: %v", err)
|
||||
}
|
||||
|
||||
actual = &appsv1.Deployment{}
|
||||
err = cli.Get(context.TODO(), types.NamespacedName{Name: deploy.IdentityProviderName, Namespace: "eclipse-che"}, actual)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to sync deployment: %v", err)
|
||||
}
|
||||
|
||||
// check ca-certs-merged revision
|
||||
cmRevision := util.FindEnv(actual.Spec.Template.Spec.Containers[0].Env, "CM_REVISION")
|
||||
if cmRevision == nil || cmRevision.Value != "1" {
|
||||
t.Fatalf("Failed to sync deployment")
|
||||
}
|
||||
|
||||
// check self-signed-certificate secret revision
|
||||
if actual.ObjectMeta.Annotations["che.self-signed-certificate.version"] != "2" {
|
||||
t.Fatalf("Failed to sync deployment")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,186 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 identityprovider
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"text/template"
|
||||
|
||||
v1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func GetKeycloakProvisionCommand(cr *v1.CheCluster) (command string, err error) {
|
||||
cheFlavor := deploy.DefaultCheFlavor(cr)
|
||||
requiredActions := (map[bool]string{true: "\"UPDATE_PASSWORD\"", false: ""})[cr.Spec.Auth.UpdateAdminPassword]
|
||||
keycloakTheme := (map[bool]string{true: "rh-sso", false: "che"})[cheFlavor == "codeready"]
|
||||
realmDisplayName := (map[bool]string{true: "CodeReady Workspaces", false: "Eclipse Che"})[cheFlavor == "codeready"]
|
||||
|
||||
script, keycloakRealm, keycloakClientId, keycloakUserEnvVar, keycloakPasswordEnvVar := getDefaults(cr)
|
||||
data := struct {
|
||||
Script string
|
||||
KeycloakAdminUserName string
|
||||
KeycloakAdminPassword string
|
||||
KeycloakRealm string
|
||||
RealmDisplayName string
|
||||
KeycloakTheme string
|
||||
CheHost string
|
||||
KeycloakClientId string
|
||||
RequiredActions string
|
||||
}{
|
||||
script,
|
||||
keycloakUserEnvVar,
|
||||
keycloakPasswordEnvVar,
|
||||
keycloakRealm,
|
||||
realmDisplayName,
|
||||
keycloakTheme,
|
||||
cr.Spec.Server.CheHost,
|
||||
keycloakClientId,
|
||||
requiredActions,
|
||||
}
|
||||
return getCommandFromTemplateFile(cr, "/tmp/keycloak-provision.sh", data)
|
||||
}
|
||||
|
||||
func GetKeycloakUpdateCommand(cr *v1.CheCluster) (command string, err error) {
|
||||
cheFlavor := deploy.DefaultCheFlavor(cr)
|
||||
realmDisplayName := (map[bool]string{true: "CodeReady Workspaces", false: "Eclipse Che"})[cheFlavor == "codeready"]
|
||||
|
||||
script, keycloakRealm, keycloakClientId, keycloakUserEnvVar, keycloakPasswordEnvVar := getDefaults(cr)
|
||||
data := struct {
|
||||
Script string
|
||||
KeycloakAdminUserName string
|
||||
KeycloakAdminPassword string
|
||||
KeycloakRealm string
|
||||
RealmDisplayName string
|
||||
CheHost string
|
||||
KeycloakClientId string
|
||||
}{
|
||||
script,
|
||||
keycloakUserEnvVar,
|
||||
keycloakPasswordEnvVar,
|
||||
keycloakRealm,
|
||||
realmDisplayName,
|
||||
cr.Spec.Server.CheHost,
|
||||
keycloakClientId,
|
||||
}
|
||||
return getCommandFromTemplateFile(cr, "/tmp/keycloak-update.sh", data)
|
||||
}
|
||||
|
||||
func GetOpenShiftIdentityProviderProvisionCommand(cr *v1.CheCluster, oAuthClientName string, oauthSecret string) (string, error) {
|
||||
isOpenShift4 := util.IsOpenShift4
|
||||
providerId := (map[bool]string{true: "openshift-v4", false: "openshift-v3"})[isOpenShift4]
|
||||
apiUrl, apiInternalUrl, err := util.GetOpenShiftAPIUrls()
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to auto-detect public OpenShift API URL. Configure it in Identity provider details page in Keycloak admin console: %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
script, keycloakRealm, keycloakClientId, keycloakUserEnvVar, keycloakPasswordEnvVar := getDefaults(cr)
|
||||
data := struct {
|
||||
Script string
|
||||
KeycloakAdminUserName string
|
||||
KeycloakAdminPassword string
|
||||
KeycloakRealm string
|
||||
ProviderId string
|
||||
OAuthClientName string
|
||||
OauthSecret string
|
||||
OpenShiftApiUrl string
|
||||
KeycloakClientId string
|
||||
}{
|
||||
script,
|
||||
keycloakUserEnvVar,
|
||||
keycloakPasswordEnvVar,
|
||||
keycloakRealm,
|
||||
providerId,
|
||||
oAuthClientName,
|
||||
oauthSecret,
|
||||
map[bool]string{true: apiInternalUrl, false: apiUrl}[apiInternalUrl != ""],
|
||||
keycloakClientId,
|
||||
}
|
||||
return getCommandFromTemplateFile(cr, "/tmp/oauth-provision.sh", data)
|
||||
}
|
||||
|
||||
func GetGitHubIdentityProviderCreateCommand(deployContext *deploy.DeployContext) (string, error) {
|
||||
cr := deployContext.CheCluster
|
||||
script, keycloakRealm, _, keycloakUserEnvVar, keycloakPasswordEnvVar := getDefaults(cr)
|
||||
data := struct {
|
||||
Script string
|
||||
KeycloakAdminUserName string
|
||||
KeycloakAdminPassword string
|
||||
KeycloakRealm string
|
||||
ProviderId string
|
||||
}{
|
||||
script,
|
||||
keycloakUserEnvVar,
|
||||
keycloakPasswordEnvVar,
|
||||
keycloakRealm,
|
||||
"github",
|
||||
}
|
||||
return getCommandFromTemplateFile(cr, "/tmp/create-github-identity-provider.sh", data)
|
||||
}
|
||||
|
||||
func GetIdentityProviderDeleteCommand(cr *v1.CheCluster, identityProvider string) (string, error) {
|
||||
script, keycloakRealm, _, keycloakUserEnvVar, keycloakPasswordEnvVar := getDefaults(cr)
|
||||
data := struct {
|
||||
Script string
|
||||
KeycloakRealm string
|
||||
KeycloakAdminUserName string
|
||||
KeycloakAdminPassword string
|
||||
ProviderId string
|
||||
}{
|
||||
script,
|
||||
keycloakRealm,
|
||||
keycloakUserEnvVar,
|
||||
keycloakPasswordEnvVar,
|
||||
identityProvider,
|
||||
}
|
||||
return getCommandFromTemplateFile(cr, "/tmp/delete-identity-provider.sh", data)
|
||||
}
|
||||
|
||||
func getCommandFromTemplateFile(cr *v1.CheCluster, templateFile string, data interface{}) (string, error) {
|
||||
cheFlavor := deploy.DefaultCheFlavor(cr)
|
||||
|
||||
file, err := ioutil.ReadFile(templateFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
template, err := template.New("Template").Parse(string(file))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
err = template.Execute(buffer, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if cheFlavor == "che" {
|
||||
return "cd /scripts && export JAVA_TOOL_OPTIONS=-Duser.home=. && " + buffer.String(), nil
|
||||
}
|
||||
return "cd /home/jboss && " + buffer.String(), nil
|
||||
}
|
||||
|
||||
func getDefaults(cr *v1.CheCluster) (string, string, string, string, string) {
|
||||
cheFlavor := deploy.DefaultCheFlavor(cr)
|
||||
keycloakRealm := util.GetValue(cr.Spec.Auth.IdentityProviderRealm, cheFlavor)
|
||||
keycloakClientId := util.GetValue(cr.Spec.Auth.IdentityProviderClientId, cheFlavor+"-public")
|
||||
if cheFlavor == "codeready" {
|
||||
return "/opt/eap/bin/kcadm.sh", keycloakRealm, keycloakClientId, "${SSO_ADMIN_USERNAME}", "${SSO_ADMIN_PASSWORD}"
|
||||
}
|
||||
|
||||
return "/opt/jboss/keycloak/bin/kcadm.sh", keycloakRealm, keycloakClientId, "${KEYCLOAK_USER}", "${KEYCLOAK_PASSWORD}"
|
||||
}
|
||||
|
|
@ -12,22 +12,15 @@
|
|||
package identityprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/gateway"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/expose"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
oauth "github.com/openshift/api/oauth/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
|
|
@ -37,17 +30,6 @@ const (
|
|||
|
||||
var (
|
||||
oAuthClientDiffOpts = cmpopts.IgnoreFields(oauth.OAuthClient{}, "TypeMeta", "ObjectMeta")
|
||||
syncItems = []func(*deploy.DeployContext) (bool, error){
|
||||
syncService,
|
||||
syncExposure,
|
||||
SyncKeycloakDeploymentToCluster,
|
||||
syncKeycloakResources,
|
||||
syncOpenShiftIdentityProvider,
|
||||
SyncGitHubOAuth,
|
||||
}
|
||||
|
||||
keycloakUpdated = false
|
||||
keycloakCheHost = ""
|
||||
)
|
||||
|
||||
type IdentityProviderReconciler struct {
|
||||
|
|
@ -59,35 +41,10 @@ func NewIdentityProviderReconciler() *IdentityProviderReconciler {
|
|||
}
|
||||
|
||||
func (ip *IdentityProviderReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile.Result, bool, error) {
|
||||
if ctx.CheCluster.Spec.Auth.ExternalIdentityProvider {
|
||||
keycloakURL := ctx.CheCluster.Spec.Auth.IdentityProviderURL
|
||||
if ctx.CheCluster.Status.KeycloakURL != keycloakURL {
|
||||
ctx.CheCluster.Status.KeycloakURL = keycloakURL
|
||||
if err := deploy.UpdateCheCRStatus(ctx, "status: Keycloak URL", keycloakURL); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
done, err := syncNativeIdentityProviderItems(ctx)
|
||||
if !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
|
||||
if ctx.CheCluster.IsNativeUserModeEnabled() {
|
||||
done, err := syncNativeIdentityProviderItems(ctx)
|
||||
if !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
for _, syncItem := range syncItems {
|
||||
done, err := syncItem(ctx)
|
||||
if !util.IsTestMode() {
|
||||
if !done {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
|
|
@ -108,93 +65,6 @@ func (ip *IdentityProviderReconciler) Finalize(ctx *deploy.DeployContext) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func syncService(deployContext *deploy.DeployContext) (bool, error) {
|
||||
return deploy.SyncServiceToCluster(
|
||||
deployContext,
|
||||
deploy.IdentityProviderName,
|
||||
[]string{"http"},
|
||||
[]int32{8080},
|
||||
deploy.IdentityProviderName)
|
||||
}
|
||||
|
||||
func syncExposure(deployContext *deploy.DeployContext) (bool, error) {
|
||||
cr := deployContext.CheCluster
|
||||
|
||||
protocol := (map[bool]string{
|
||||
true: "https",
|
||||
false: "http"})[cr.Spec.Server.TlsSupport]
|
||||
endpoint, done, err := expose.Expose(
|
||||
deployContext,
|
||||
deploy.IdentityProviderName,
|
||||
cr.Spec.Auth.IdentityProviderRoute,
|
||||
cr.Spec.Auth.IdentityProviderIngress,
|
||||
createGatewayConfig(deployContext.CheCluster))
|
||||
if !done {
|
||||
return false, err
|
||||
}
|
||||
|
||||
keycloakURL := protocol + "://" + endpoint
|
||||
if cr.Spec.Auth.IdentityProviderURL != keycloakURL {
|
||||
cr.Spec.Auth.IdentityProviderURL = keycloakURL
|
||||
if err := deploy.UpdateCheCRSpec(deployContext, "Keycloak URL", keycloakURL); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
cr.Status.KeycloakURL = keycloakURL
|
||||
if err := deploy.UpdateCheCRStatus(deployContext, "Keycloak URL", keycloakURL); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func syncKeycloakResources(deployContext *deploy.DeployContext) (bool, error) {
|
||||
if !util.IsTestMode() {
|
||||
cr := deployContext.CheCluster
|
||||
if !cr.Status.KeycloakProvisoned {
|
||||
if err := ProvisionKeycloakResources(deployContext); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for {
|
||||
cr.Status.KeycloakProvisoned = true
|
||||
if err := deploy.UpdateCheCRStatus(deployContext, "status: provisioned with Keycloak", "true"); err != nil &&
|
||||
apierrors.IsConflict(err) {
|
||||
|
||||
deploy.ReloadCheClusterCR(deployContext)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Updates keycloak if chehost has been changed
|
||||
if !keycloakUpdated || keycloakCheHost != deployContext.CheCluster.Spec.Server.CheHost {
|
||||
if _, err := util.K8sclient.ExecIntoPod(
|
||||
deployContext.CheCluster,
|
||||
deploy.IdentityProviderName,
|
||||
GetKeycloakUpdateCommand,
|
||||
"Update redirect URI-s and webOrigins"); err != nil {
|
||||
return false, err
|
||||
} else {
|
||||
keycloakUpdated = true
|
||||
keycloakCheHost = deployContext.CheCluster.Spec.Server.CheHost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func syncOpenShiftIdentityProvider(deployContext *deploy.DeployContext) (bool, error) {
|
||||
cr := deployContext.CheCluster
|
||||
if util.IsOpenShift && cr.IsOpenShiftOAuthEnabled() {
|
||||
return SyncOpenShiftIdentityProviderItems(deployContext)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func syncNativeIdentityProviderItems(deployContext *deploy.DeployContext) (bool, error) {
|
||||
cr := deployContext.CheCluster
|
||||
|
||||
|
|
@ -222,55 +92,6 @@ func syncNativeIdentityProviderItems(deployContext *deploy.DeployContext) (bool,
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func SyncOpenShiftIdentityProviderItems(deployContext *deploy.DeployContext) (bool, error) {
|
||||
cr := deployContext.CheCluster
|
||||
|
||||
if err := resolveOpenshiftOAuthClientName(deployContext); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := resolveOpenshiftOAuthClientSecret(deployContext); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
keycloakURL := cr.Spec.Auth.IdentityProviderURL
|
||||
cheFlavor := deploy.DefaultCheFlavor(cr)
|
||||
keycloakRealm := util.GetValue(cr.Spec.Auth.IdentityProviderRealm, cheFlavor)
|
||||
oAuthClient := getKeycloakOAuthClientSpec(cr.Spec.Auth.OAuthClientName, cr.Spec.Auth.OAuthSecret, keycloakURL, keycloakRealm, util.IsOpenShift4)
|
||||
provisioned, err := deploy.Sync(deployContext, oAuthClient, oAuthClientDiffOpts)
|
||||
if !provisioned {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !util.IsTestMode() {
|
||||
if !cr.Status.OpenShiftoAuthProvisioned {
|
||||
// note that this uses the instance.Spec.Auth.IdentityProviderRealm and instance.Spec.Auth.IdentityProviderClientId.
|
||||
// because we're not doing much of a change detection on those fields, we can't react on them changing here.
|
||||
_, err := util.K8sclient.ExecIntoPod(
|
||||
cr,
|
||||
deploy.IdentityProviderName,
|
||||
func(cr *orgv1.CheCluster) (string, error) {
|
||||
return GetOpenShiftIdentityProviderProvisionCommand(cr, cr.Spec.Auth.OAuthClientName, cr.Spec.Auth.OAuthSecret)
|
||||
},
|
||||
"Create OpenShift identity provider")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for {
|
||||
cr.Status.OpenShiftoAuthProvisioned = true
|
||||
if err := deploy.UpdateCheCRStatus(deployContext, "status: provisioned with OpenShift identity provider", "true"); err != nil &&
|
||||
apierrors.IsConflict(err) {
|
||||
|
||||
deploy.ReloadCheClusterCR(deployContext)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func resolveOpenshiftOAuthClientName(deployContext *deploy.DeployContext) error {
|
||||
cr := deployContext.CheCluster
|
||||
oAuthClientName := cr.Spec.Auth.OAuthClientName
|
||||
|
|
@ -296,157 +117,3 @@ func resolveOpenshiftOAuthClientSecret(deployContext *deploy.DeployContext) erro
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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
|
||||
}
|
||||
|
||||
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() {
|
||||
_, err := util.K8sclient.ExecIntoPod(
|
||||
cr,
|
||||
deploy.IdentityProviderName,
|
||||
func(cr *orgv1.CheCluster) (string, error) {
|
||||
return GetGitHubIdentityProviderCreateCommand(deployContext)
|
||||
},
|
||||
"Create GitHub OAuth")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
cr.Status.GitHubOAuthProvisioned = true
|
||||
if err := deploy.UpdateCheCRStatus(deployContext, "status: GitHub OAuth provisioned", "true"); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if cr.Status.GitHubOAuthProvisioned {
|
||||
if !util.IsTestMode() {
|
||||
_, err := util.K8sclient.ExecIntoPod(
|
||||
cr,
|
||||
deploy.IdentityProviderName,
|
||||
func(cr *orgv1.CheCluster) (string, error) {
|
||||
return GetIdentityProviderDeleteCommand(cr, "github")
|
||||
},
|
||||
"Delete GitHub OAuth")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
cr.Status.GitHubOAuthProvisioned = false
|
||||
if err := deploy.UpdateCheCRStatus(deployContext, "status: GitHub OAuth provisioned", "false"); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func deleteIdentityProvider(ctx *deploy.DeployContext) error {
|
||||
if !ctx.CheCluster.IsOpenShiftOAuthEnabled() && ctx.CheCluster.Status.OpenShiftoAuthProvisioned == true {
|
||||
keycloakDeployment := &appsv1.Deployment{}
|
||||
if err := ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: deploy.IdentityProviderName, Namespace: ctx.CheCluster.Namespace}, keycloakDeployment); err != nil {
|
||||
logrus.Errorf("Deployment %s not found: %s", keycloakDeployment.Name, err.Error())
|
||||
}
|
||||
|
||||
providerName := "openshift-v3"
|
||||
if util.IsOpenShift4 {
|
||||
providerName = "openshift-v4"
|
||||
}
|
||||
|
||||
_, err := util.K8sclient.ExecIntoPod(
|
||||
ctx.CheCluster,
|
||||
keycloakDeployment.Name,
|
||||
func(cr *orgv1.CheCluster) (string, error) {
|
||||
return GetIdentityProviderDeleteCommand(ctx.CheCluster, providerName)
|
||||
},
|
||||
"delete OpenShift identity provider")
|
||||
if err == nil {
|
||||
oAuthClient := &oauth.OAuthClient{}
|
||||
oAuthClientName := ctx.CheCluster.Spec.Auth.OAuthClientName
|
||||
err := deploy.DeleteObjectWithFinalizer(ctx, types.NamespacedName{Name: oAuthClientName}, &oauth.OAuthClient{}, OAuthFinalizerName)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to delete %s %s: %s", oAuthClient.Kind, oAuthClient.Name, err.Error())
|
||||
}
|
||||
|
||||
for {
|
||||
ctx.CheCluster.Status.OpenShiftoAuthProvisioned = false
|
||||
if err := deploy.UpdateCheCRStatus(ctx, "OpenShiftoAuthProvisioned", "false"); err != nil {
|
||||
if apierrors.IsConflict(err) {
|
||||
deploy.ReloadCheClusterCR(ctx)
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
for {
|
||||
ctx.CheCluster.Spec.Auth.OAuthSecret = ""
|
||||
ctx.CheCluster.Spec.Auth.OAuthClientName = ""
|
||||
updateFields := map[string]string{
|
||||
"oAuthSecret": "",
|
||||
"oAuthClientName": "",
|
||||
}
|
||||
|
||||
if err := deploy.UpdateCheCRSpecByFields(ctx, updateFields); err != nil {
|
||||
if apierrors.IsConflict(err) {
|
||||
deploy.ReloadCheClusterCR(ctx)
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createGatewayConfig(cheCluster *orgv1.CheCluster) *gateway.TraefikConfig {
|
||||
cfg := gateway.CreateCommonTraefikConfig(
|
||||
deploy.IdentityProviderName,
|
||||
"PathPrefix(`/auth`)",
|
||||
10,
|
||||
"http://"+deploy.IdentityProviderName+":8080",
|
||||
[]string{})
|
||||
|
||||
if util.IsOpenShift && cheCluster.IsNativeUserModeEnabled() {
|
||||
cfg.AddAuthHeaderRewrite(deploy.IdentityProviderName)
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,211 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 identityprovider
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/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"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSyncGitHubOAuth(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
initCR *orgv1.CheCluster
|
||||
expectedCR *orgv1.CheCluster
|
||||
initObjects []runtime.Object
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Should provision GitHub OAuth with legacy secret",
|
||||
initCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
ResourceVersion: "0",
|
||||
},
|
||||
},
|
||||
expectedCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
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-credentials",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
deploy.KubernetesComponentLabelKey: "keycloak-secret",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
deploy.CheEclipseOrgGithubOAuthCredentials: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"key": []byte("key-data"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should provision GitHub OAuth",
|
||||
initCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
ResourceVersion: "0",
|
||||
},
|
||||
},
|
||||
expectedCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
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{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
ResourceVersion: "0",
|
||||
},
|
||||
},
|
||||
expectedCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
ResourceVersion: "0",
|
||||
},
|
||||
},
|
||||
initObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "github-credentials",
|
||||
Namespace: "eclipse-che",
|
||||
Labels: map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
deploy.KubernetesComponentLabelKey: "keycloak-secret",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"key": []byte("key-data"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should delete GitHub OAuth",
|
||||
initCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
ResourceVersion: "0",
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
GitHubOAuthProvisioned: true,
|
||||
},
|
||||
},
|
||||
expectedCR: &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "che-cluster",
|
||||
Namespace: "eclipse-che",
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
GitHubOAuthProvisioned: false,
|
||||
},
|
||||
},
|
||||
initObjects: []runtime.Object{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true)))
|
||||
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
testCase.initObjects = append(testCase.initObjects, testCase.initCR)
|
||||
cli := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
|
||||
|
||||
deployContext := &deploy.DeployContext{
|
||||
CheCluster: testCase.initCR,
|
||||
ClusterAPI: deploy.ClusterAPI{
|
||||
Client: cli,
|
||||
Scheme: scheme.Scheme,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := SyncGitHubOAuth(deployContext)
|
||||
if err != nil {
|
||||
t.Fatalf("Error mounting secret: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(testCase.expectedCR, testCase.initCR) {
|
||||
t.Errorf("Expected CR and CR returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedCR, testCase.initCR))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -12,33 +12,10 @@
|
|||
package identityprovider
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
oauth "github.com/openshift/api/oauth/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func getKeycloakOAuthClientSpec(name string, oauthSecret string, keycloakURL string, keycloakRealm string, isOpenShift4 bool) *oauth.OAuthClient {
|
||||
providerName := "openshift-v3"
|
||||
if isOpenShift4 {
|
||||
providerName = "openshift-v4"
|
||||
}
|
||||
|
||||
redirectURLSuffix := "/realms/" + keycloakRealm + "/broker/" + providerName + "/endpoint"
|
||||
redirectURIs := []string{
|
||||
keycloakURL + redirectURLSuffix,
|
||||
}
|
||||
|
||||
keycloakURL = strings.NewReplacer("https://", "", "http://", "").Replace(keycloakURL)
|
||||
if !strings.Contains(keycloakURL, "://") {
|
||||
redirectURIs = []string{
|
||||
"http://" + keycloakURL + redirectURLSuffix,
|
||||
"https://" + keycloakURL + redirectURLSuffix,
|
||||
}
|
||||
}
|
||||
return getOAuthClientSpec(name, oauthSecret, redirectURIs)
|
||||
}
|
||||
|
||||
func getOAuthClientSpec(name string, oauthSecret string, redirectURIs []string) *oauth.OAuthClient {
|
||||
return &oauth.OAuthClient{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 identityprovider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func GetWaitForKeycloakInitContainer(deployContext *deploy.DeployContext) (*corev1.Container, error) {
|
||||
keycloakReadinessCheckerImage := deploy.DefaultKeycloakImage(deployContext.CheCluster)
|
||||
imagePullPolicy := corev1.PullPolicy(deploy.DefaultPullPolicyFromDockerImage(keycloakReadinessCheckerImage))
|
||||
|
||||
return &corev1.Container{
|
||||
Name: "wait-for-identity-provider",
|
||||
Image: keycloakReadinessCheckerImage,
|
||||
ImagePullPolicy: imagePullPolicy,
|
||||
Command: []string{
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
getCheckKeycloakReadinessScript(deployContext),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getCheckKeycloakReadinessScript(deployContext *deploy.DeployContext) string {
|
||||
cheFlavor := deploy.DefaultCheFlavor(deployContext.CheCluster)
|
||||
realmName := util.GetValue(deployContext.CheCluster.Spec.Auth.IdentityProviderRealm, cheFlavor)
|
||||
url := fmt.Sprintf("%s/realms/%s/.well-known/openid-configuration", deployContext.CheCluster.Status.KeycloakURL, realmName)
|
||||
// URL example: https://keycloak-eclipse-che.192.168.99.254.nip.io/auth/realms/che/.well-known/openid-configuration
|
||||
|
||||
script := `
|
||||
while : ; do
|
||||
response_code=$(curl --connect-timeout 5 -kI %s 2>/dev/null | awk 'NR==1 {print $2}')
|
||||
if [ "$response_code" == "200" ]; then
|
||||
break
|
||||
fi
|
||||
echo 'waiting for Identity provider'
|
||||
sleep 2
|
||||
done
|
||||
`
|
||||
|
||||
return fmt.Sprintf(script, url)
|
||||
}
|
||||
|
|
@ -123,9 +123,6 @@ func TestImagePullerConfiguration(t *testing.T) {
|
|||
ConfigMapName: "k8s-image-puller",
|
||||
},
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
initObjects: []runtime.Object{
|
||||
|
|
@ -557,9 +554,6 @@ func InitCheCRWithImagePullerEnabled() *orgv1.CheCluster {
|
|||
ImagePuller: orgv1.CheClusterSpecImagePuller{
|
||||
Enable: true,
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -582,9 +576,6 @@ func InitCheCRWithImagePullerFinalizer() *orgv1.CheCluster {
|
|||
ImagePuller: orgv1.CheClusterSpecImagePuller{
|
||||
Enable: true,
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -603,9 +594,6 @@ func InitCheCRWithImagePullerFinalizerAndDeletionTimestamp() *orgv1.CheCluster {
|
|||
ImagePuller: orgv1.CheClusterSpecImagePuller{
|
||||
Enable: true,
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -628,9 +616,6 @@ func ExpectedCheCRWithImagePullerFinalizer() *orgv1.CheCluster {
|
|||
ImagePuller: orgv1.CheClusterSpecImagePuller{
|
||||
Enable: true,
|
||||
},
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -675,9 +660,6 @@ func InitCheCRWithImagePullerEnabledAndDefaultValuesSet() *orgv1.CheCluster {
|
|||
ConfigMapName: "k8s-image-puller",
|
||||
},
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -704,9 +686,6 @@ func InitCheCRWithImagePullerEnabledAndImagesSet(images string) *orgv1.CheCluste
|
|||
Images: images,
|
||||
},
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -728,9 +707,6 @@ func InitCheCRWithImagePullerEnabledAndNewValuesSet() *orgv1.CheCluster {
|
|||
ConfigMapName: "k8s-image-puller-trigger-update",
|
||||
},
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
networking "k8s.io/api/networking/v1"
|
||||
v1 "k8s.io/api/networking/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
|
@ -52,11 +53,6 @@ func TestIngressSpec(t *testing.T) {
|
|||
Namespace: "eclipse-che",
|
||||
Name: cheFlavor,
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
K8s: orgv1.CheClusterSpecK8SOnly{
|
||||
SingleHostExposureType: GatewaySingleHostExposureType,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
|
|
@ -90,7 +86,7 @@ func TestIngressSpec(t *testing.T) {
|
|||
"kubernetes.io/ingress.class": "nginx",
|
||||
"nginx.ingress.kubernetes.io/proxy-connect-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": "false",
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": "true",
|
||||
"nginx.ingress.kubernetes.io/proxy-buffer-size": "16k",
|
||||
"nginx.org/websocket-services": "che-host",
|
||||
"annotation-key": "annotation-value",
|
||||
|
|
@ -101,6 +97,7 @@ func TestIngressSpec(t *testing.T) {
|
|||
APIVersion: networking.SchemeGroupVersion.String(),
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
TLS: []v1.IngressTLS{{Hosts: []string{"test-host"}}},
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "test-host",
|
||||
|
|
@ -158,7 +155,7 @@ func TestIngressSpec(t *testing.T) {
|
|||
"nginx.ingress.kubernetes.io/proxy-connect-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/proxy-buffer-size": "16k",
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": "false",
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": "true",
|
||||
"nginx.org/websocket-services": "che-host",
|
||||
"annotation-key": "annotation-value",
|
||||
},
|
||||
|
|
@ -168,6 +165,7 @@ func TestIngressSpec(t *testing.T) {
|
|||
APIVersion: networking.SchemeGroupVersion.String(),
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
TLS: []v1.IngressTLS{{Hosts: []string{"test-host"}}},
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "test-host",
|
||||
|
|
@ -224,7 +222,7 @@ func TestIngressSpec(t *testing.T) {
|
|||
"nginx.ingress.kubernetes.io/proxy-connect-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/proxy-buffer-size": "16k",
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": "false",
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": "true",
|
||||
"nginx.org/websocket-services": "che-host",
|
||||
"annotation-key": "annotation-value",
|
||||
},
|
||||
|
|
@ -234,6 +232,7 @@ func TestIngressSpec(t *testing.T) {
|
|||
APIVersion: networking.SchemeGroupVersion.String(),
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
TLS: []v1.IngressTLS{{Hosts: []string{"test-host"}}},
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "test-host",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ package deploy
|
|||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
|
|
@ -63,9 +62,6 @@ func GetIngressSpec(
|
|||
component string) (ingressUrl string, i *networking.Ingress) {
|
||||
|
||||
cheFlavor := DefaultCheFlavor(deployContext.CheCluster)
|
||||
tlsSupport := deployContext.CheCluster.Spec.Server.TlsSupport
|
||||
ingressStrategy := util.GetServerExposureStrategy(deployContext.CheCluster)
|
||||
exposureType := GetSingleHostExposureType(deployContext.CheCluster)
|
||||
ingressDomain := deployContext.CheCluster.Spec.K8s.IngressDomain
|
||||
tlsSecretName := deployContext.CheCluster.Spec.K8s.TlsSecretName
|
||||
ingressClass := util.GetValue(deployContext.CheCluster.Spec.K8s.IngressClass, DefaultIngressClass)
|
||||
|
|
@ -73,24 +69,18 @@ func GetIngressSpec(
|
|||
MergeLabels(labels, ingressCustomSettings.Labels)
|
||||
pathType := networking.PathTypeImplementationSpecific
|
||||
|
||||
if tlsSupport {
|
||||
// for server and dashboard ingresses
|
||||
if (component == cheFlavor || component == cheFlavor+"-dashboard") && deployContext.CheCluster.Spec.Server.CheHostTLSSecret != "" {
|
||||
tlsSecretName = deployContext.CheCluster.Spec.Server.CheHostTLSSecret
|
||||
}
|
||||
// for server and dashboard ingresses
|
||||
if (component == cheFlavor || component == cheFlavor+"-dashboard") && deployContext.CheCluster.Spec.Server.CheHostTLSSecret != "" {
|
||||
tlsSecretName = deployContext.CheCluster.Spec.Server.CheHostTLSSecret
|
||||
}
|
||||
|
||||
if host == "" {
|
||||
if ingressStrategy == "multi-host" {
|
||||
host = component + "-" + deployContext.CheCluster.Namespace + "." + ingressDomain
|
||||
} else if ingressStrategy == "single-host" {
|
||||
host = ingressDomain
|
||||
}
|
||||
host = ingressDomain
|
||||
}
|
||||
|
||||
var endpointPath, ingressPath string
|
||||
if path == "" {
|
||||
endpointPath, ingressPath = evaluatePath(component, ingressStrategy)
|
||||
endpointPath, ingressPath = evaluatePath(component)
|
||||
} else {
|
||||
ingressPath = path
|
||||
endpointPath = path
|
||||
|
|
@ -100,15 +90,14 @@ func GetIngressSpec(
|
|||
"kubernetes.io/ingress.class": ingressClass,
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/proxy-connect-timeout": "3600",
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": strconv.FormatBool(tlsSupport),
|
||||
"nginx.ingress.kubernetes.io/ssl-redirect": "true",
|
||||
}
|
||||
if ingressStrategy != "multi-host" && (component == DevfileRegistryName || component == PluginRegistryName) {
|
||||
if component == DevfileRegistryName || component == PluginRegistryName {
|
||||
annotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$1"
|
||||
}
|
||||
// Set bigger proxy buffer size to prevent 502 auth error.
|
||||
if component == IdentityProviderName || exposureType == GatewaySingleHostExposureType {
|
||||
annotations["nginx.ingress.kubernetes.io/proxy-buffer-size"] = "16k"
|
||||
}
|
||||
annotations["nginx.ingress.kubernetes.io/proxy-buffer-size"] = "16k"
|
||||
|
||||
for k, v := range ingressCustomSettings.Annotations {
|
||||
annotations[k] = v
|
||||
}
|
||||
|
|
@ -176,13 +165,11 @@ func GetIngressSpec(
|
|||
ingress.ObjectMeta.Annotations["nginx.org/websocket-services"] = serviceName
|
||||
}
|
||||
|
||||
if tlsSupport {
|
||||
ingress.Spec.TLS = []networking.IngressTLS{
|
||||
{
|
||||
Hosts: []string{host},
|
||||
SecretName: tlsSecretName,
|
||||
},
|
||||
}
|
||||
ingress.Spec.TLS = []networking.IngressTLS{
|
||||
{
|
||||
Hosts: []string{host},
|
||||
SecretName: tlsSecretName,
|
||||
},
|
||||
}
|
||||
|
||||
return host + endpointPath, ingress
|
||||
|
|
@ -190,30 +177,17 @@ func GetIngressSpec(
|
|||
|
||||
// evaluatePath evaluates ingress path (one which is used for rule)
|
||||
// and endpoint path (one which client should use during endpoint accessing)
|
||||
func evaluatePath(component, ingressStrategy string) (endpointPath, ingressPath string) {
|
||||
if ingressStrategy == "multi-host" {
|
||||
func evaluatePath(component string) (endpointPath, ingressPath string) {
|
||||
switch component {
|
||||
case DevfileRegistryName:
|
||||
fallthrough
|
||||
case PluginRegistryName:
|
||||
endpointPath = "/" + component
|
||||
ingressPath = endpointPath + "/(.*)"
|
||||
default:
|
||||
ingressPath = "/"
|
||||
endpointPath = "/"
|
||||
// Keycloak needs special rule in multihost. It's exposed on / which redirects to /auth
|
||||
// clients which does not support redirects needs /auth be explicitely set
|
||||
if component == IdentityProviderName {
|
||||
endpointPath = "/auth"
|
||||
}
|
||||
} else {
|
||||
switch component {
|
||||
case IdentityProviderName:
|
||||
endpointPath = "/auth"
|
||||
ingressPath = endpointPath + "/(.*)"
|
||||
case DevfileRegistryName:
|
||||
fallthrough
|
||||
case PluginRegistryName:
|
||||
endpointPath = "/" + component
|
||||
ingressPath = endpointPath + "/(.*)"
|
||||
default:
|
||||
ingressPath = "/"
|
||||
endpointPath = "/"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return endpointPath, ingressPath
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,8 +91,6 @@ func (m *Migrator) migrate(ctx *deploy.DeployContext) (bool, error) {
|
|||
// - spec.server.gitSelfSignedCert ('che-git-self-signed-cert' config map)
|
||||
// - spec.server.proxySecret
|
||||
// - spec.database.chePostgresSecret
|
||||
// - spec.auth.identityProviderSecret
|
||||
// - spec.auth.identityProviderPostgresSecret
|
||||
// - spec.k8s.tlsSecretName
|
||||
// Note, most of the objects above are autogenerated and do not require any migration,
|
||||
// but to handle the case when some were created manually or operator updated, the check is done here.
|
||||
|
|
@ -134,19 +132,6 @@ func addPartOfCheLabeltoUserDefinedObjects(ctx *deploy.DeployContext) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Keycloak related secrets
|
||||
if ctx.CheCluster.Spec.Auth.IdentityProviderSecret != "" {
|
||||
if err := addPartOfCheLabelToSecret(ctx, ctx.CheCluster.Spec.Auth.IdentityProviderSecret); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Spec.Auth.IdentityProviderPostgresSecret != "" {
|
||||
if err := addPartOfCheLabelToSecret(ctx, ctx.CheCluster.Spec.Auth.IdentityProviderPostgresSecret); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy config map with additional CA certificates
|
||||
if ctx.CheCluster.Spec.Server.ServerTrustStoreConfigMapName != "" {
|
||||
if err := addPartOfCheLabelToConfigMap(ctx, ctx.CheCluster.Spec.Server.ServerTrustStoreConfigMapName); err != nil {
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 openshiftoauth
|
||||
|
||||
import "github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
|
||||
func init() {
|
||||
err := deploy.InitTestDefaultsFromDeployment("../../../config/manager/manager.yaml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2012-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 openshiftoauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
userv1 "github.com/openshift/api/user/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
const (
|
||||
warningNoIdentityProvidersMessage = "No Openshift identity providers."
|
||||
|
||||
AddIdentityProviderMessage = "Openshift oAuth was disabled. How to add identity provider read in the Help Link:"
|
||||
warningNoRealUsersMessage = "No real users. Openshift oAuth was disabled. How to add new user read in the Help Link:"
|
||||
failedUnableToGetOpenshiftUsers = "Unable to get users on the OpenShift cluster."
|
||||
|
||||
howToAddIdentityProviderLinkOS4 = "https://docs.openshift.com/container-platform/latest/authentication/understanding-identity-provider.html#identity-provider-overview_understanding-identity-provider"
|
||||
howToConfigureOAuthLinkOS3 = "https://docs.openshift.com/container-platform/3.11/install_config/configuring_authentication.html"
|
||||
)
|
||||
|
||||
type OpenShiftOAuth struct {
|
||||
openShiftOAuthUser *OpenShiftOAuthUser
|
||||
}
|
||||
|
||||
func NewOpenShiftOAuth(openShiftOAuthUser *OpenShiftOAuthUser) *OpenShiftOAuth {
|
||||
return &OpenShiftOAuth{
|
||||
openShiftOAuthUser,
|
||||
}
|
||||
}
|
||||
|
||||
func (oo *OpenShiftOAuth) Reconcile(ctx *deploy.DeployContext) (reconcile.Result, bool, error) {
|
||||
if util.IsOpenShift && ctx.CheCluster.Spec.Auth.OpenShiftoAuth == nil {
|
||||
return oo.enableOpenShiftOAuth(ctx)
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
func (oo *OpenShiftOAuth) Finalize(ctx *deploy.DeployContext) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (oo *OpenShiftOAuth) enableOpenShiftOAuth(ctx *deploy.DeployContext) (reconcile.Result, bool, error) {
|
||||
oauth := false
|
||||
if util.IsOpenShift4 {
|
||||
openshitOAuth, err := GetOpenshiftOAuth(ctx)
|
||||
if err != nil {
|
||||
logrus.Error("Unable to get Openshift oAuth. Cause: " + err.Error())
|
||||
} else {
|
||||
if len(openshitOAuth.Spec.IdentityProviders) > 0 {
|
||||
oauth = true
|
||||
} else if ctx.CheCluster.IsNativeUserModeEnabled() {
|
||||
// enable OpenShift OAuth without adding initial OpenShift OAuth user
|
||||
// since kubeadmin is a valid user for native user mode
|
||||
oauth = true
|
||||
} else if ctx.CheCluster.IsOpenShiftOAuthUserConfigured() {
|
||||
provisioned, err := oo.openShiftOAuthUser.Create(ctx)
|
||||
if err != nil {
|
||||
logrus.Error(warningNoIdentityProvidersMessage + " Operator tried to create initial OpenShift OAuth user for HTPasswd identity provider, but failed. Cause: " + err.Error())
|
||||
logrus.Info("To enable OpenShift OAuth, please add identity provider first: " + howToAddIdentityProviderLinkOS4)
|
||||
|
||||
// Don't try to create initial user any more, che-operator shouldn't hang on this step.
|
||||
ctx.CheCluster.Spec.Auth.InitialOpenShiftOAuthUser = nil
|
||||
if err := deploy.UpdateCheCRStatus(ctx, "initialOpenShiftOAuthUser", ""); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
oauth = false
|
||||
} else {
|
||||
if !provisioned {
|
||||
// let's wait some time
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
oauth = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // Openshift 3
|
||||
users := &userv1.UserList{}
|
||||
listOptions := &client.ListOptions{}
|
||||
if err := ctx.ClusterAPI.NonCachingClient.List(context.TODO(), users, listOptions); err != nil {
|
||||
logrus.Error(failedUnableToGetOpenshiftUsers + " Cause: " + err.Error())
|
||||
} else {
|
||||
oauth = len(users.Items) >= 1
|
||||
if !oauth {
|
||||
logrus.Warn(warningNoRealUsersMessage + " " + howToConfigureOAuthLinkOS3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newOAuthValue := util.NewBoolPointer(oauth)
|
||||
if !reflect.DeepEqual(newOAuthValue, ctx.CheCluster.Spec.Auth.OpenShiftoAuth) {
|
||||
ctx.CheCluster.Spec.Auth.OpenShiftoAuth = newOAuthValue
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "openShiftoAuth", strconv.FormatBool(oauth)); err != nil {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2012-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 openshiftoauth
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
configv1 "github.com/openshift/api/config/v1"
|
||||
oauthv1 "github.com/openshift/api/oauth/v1"
|
||||
userv1 "github.com/openshift/api/user/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/pointer"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
nonEmptyUserList = &userv1.UserList{
|
||||
Items: []userv1.User{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "user1",
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "user2",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
oAuthWithNoIdentityProviders = &configv1.OAuth{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cluster",
|
||||
},
|
||||
}
|
||||
oAuthWithIdentityProvider = &configv1.OAuth{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cluster",
|
||||
},
|
||||
Spec: configv1.OAuthSpec{
|
||||
IdentityProviders: []configv1.IdentityProvider{
|
||||
{
|
||||
Name: "htpasswd",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
proxy = &configv1.Proxy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cluster",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestCaseAutoDetectOAuth(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
initObjects []runtime.Object
|
||||
isOpenshift4 bool
|
||||
initialOAuthValue *bool
|
||||
oAuthExpected *bool
|
||||
initialOpenShiftOAuthUserEnabled *bool
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "che-operator should auto enable oAuth when Che CR with oAuth nil value on the Openshift 3 with users > 0",
|
||||
initObjects: []runtime.Object{
|
||||
nonEmptyUserList,
|
||||
&oauthv1.OAuthClient{},
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: nil,
|
||||
oAuthExpected: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should auto disable oAuth when Che CR with nil oAuth on the Openshift 3 with no users",
|
||||
initObjects: []runtime.Object{
|
||||
&userv1.UserList{},
|
||||
&oauthv1.OAuthClient{},
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(false),
|
||||
oAuthExpected: pointer.BoolPtr(false),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = true even if there no users on the Openshift 3",
|
||||
initObjects: []runtime.Object{
|
||||
&userv1.UserList{},
|
||||
&oauthv1.OAuthClient{},
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(true),
|
||||
oAuthExpected: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = true even if there are some users on the Openshift 3",
|
||||
initObjects: []runtime.Object{
|
||||
nonEmptyUserList,
|
||||
&oauthv1.OAuthClient{},
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(true),
|
||||
oAuthExpected: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = false even if there are some users on the Openshift 3",
|
||||
initObjects: []runtime.Object{
|
||||
nonEmptyUserList,
|
||||
&oauthv1.OAuthClient{},
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(false),
|
||||
oAuthExpected: pointer.BoolPtr(false),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = false even if no users on the Openshift 3",
|
||||
initObjects: []runtime.Object{
|
||||
&userv1.UserList{},
|
||||
&oauthv1.OAuthClient{},
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(false),
|
||||
oAuthExpected: pointer.BoolPtr(false),
|
||||
},
|
||||
{
|
||||
name: "che-operator should auto enable oAuth when Che CR with nil value on the Openshift 4 with identity providers",
|
||||
initObjects: []runtime.Object{
|
||||
oAuthWithIdentityProvider,
|
||||
proxy,
|
||||
},
|
||||
isOpenshift4: true,
|
||||
initialOAuthValue: nil,
|
||||
oAuthExpected: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = true even if there no indentity providers on the Openshift 4",
|
||||
initObjects: []runtime.Object{
|
||||
oAuthWithNoIdentityProviders,
|
||||
proxy,
|
||||
},
|
||||
isOpenshift4: true,
|
||||
initialOAuthValue: pointer.BoolPtr(true),
|
||||
oAuthExpected: pointer.BoolPtr(true),
|
||||
initialOpenShiftOAuthUserEnabled: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = true even if there are some users on the Openshift 4",
|
||||
initObjects: []runtime.Object{
|
||||
oAuthWithIdentityProvider,
|
||||
proxy,
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(true),
|
||||
oAuthExpected: pointer.BoolPtr(true),
|
||||
initialOpenShiftOAuthUserEnabled: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = false even if there no indentity providers on the Openshift 4",
|
||||
initObjects: []runtime.Object{
|
||||
oAuthWithNoIdentityProviders,
|
||||
proxy,
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(false),
|
||||
oAuthExpected: pointer.BoolPtr(false),
|
||||
},
|
||||
{
|
||||
name: "che-operator should respect oAuth = false even if there are some users on the Openshift 4",
|
||||
initObjects: []runtime.Object{
|
||||
oAuthWithIdentityProvider,
|
||||
proxy,
|
||||
},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: pointer.BoolPtr(false),
|
||||
oAuthExpected: pointer.BoolPtr(false),
|
||||
},
|
||||
{
|
||||
name: "che-operator should auto disable oAuth on error retieve identity providers",
|
||||
initObjects: []runtime.Object{},
|
||||
isOpenshift4: false,
|
||||
initialOAuthValue: nil,
|
||||
initialOpenShiftOAuthUserEnabled: pointer.BoolPtr(true),
|
||||
oAuthExpected: pointer.BoolPtr(false),
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true)))
|
||||
|
||||
checluster := &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: os.Getenv("CHE_FLAVOR"),
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: testCase.initialOAuthValue,
|
||||
InitialOpenShiftOAuthUser: testCase.initialOpenShiftOAuthUserEnabled,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
util.IsOpenShift = true
|
||||
util.IsOpenShift4 = testCase.isOpenshift4
|
||||
deployContext := deploy.GetTestDeployContext(checluster, testCase.initObjects)
|
||||
|
||||
openShiftOAuth := NewOpenShiftOAuth(NewOpenShiftOAuthUser())
|
||||
_, done, err := openShiftOAuth.Reconcile(deployContext)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, done)
|
||||
|
||||
assert.NotNil(t, deployContext.CheCluster.Spec.Auth.OpenShiftoAuth)
|
||||
assert.Equal(t, *testCase.oAuthExpected, *deployContext.CheCluster.Spec.Auth.OpenShiftoAuth)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,321 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 openshiftoauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
configv1 "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/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
const (
|
||||
HtpasswdIdentityProviderName = "htpasswd-eclipse-che"
|
||||
HtpasswdSecretName = "htpasswd-eclipse-che"
|
||||
OcConfigNamespace = "openshift-config"
|
||||
OpenShiftOAuthUserCredentialsSecret = "openshift-oauth-user-credentials"
|
||||
OpenshiftOauthUserFinalizerName = "openshift-oauth-user.finalizers.che.eclipse.org"
|
||||
)
|
||||
|
||||
type IOpenShiftOAuthUser interface {
|
||||
Create(ctx *deploy.DeployContext) (bool, error)
|
||||
Delete(ctx *deploy.DeployContext) error
|
||||
}
|
||||
|
||||
type OpenShiftOAuthUser struct {
|
||||
userPassword string
|
||||
runnable util.Runnable
|
||||
|
||||
deploy.Reconcilable
|
||||
IOpenShiftOAuthUser
|
||||
}
|
||||
|
||||
func NewOpenShiftOAuthUser() *OpenShiftOAuthUser {
|
||||
return &OpenShiftOAuthUser{
|
||||
userPassword: util.GeneratePasswd(6),
|
||||
runnable: util.NewRunnable(), // real process, mock for tests
|
||||
}
|
||||
}
|
||||
|
||||
func (oou *OpenShiftOAuthUser) Reconcile(ctx *deploy.DeployContext) (reconcile.Result, bool, error) {
|
||||
if !util.IsOpenShift4 {
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
if ctx.CheCluster.IsOpenShiftOAuthUserConfigured() &&
|
||||
(ctx.CheCluster.Spec.Auth.OpenShiftoAuth == nil || *ctx.CheCluster.Spec.Auth.OpenShiftoAuth) {
|
||||
|
||||
done, err := oou.Create(ctx)
|
||||
if !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
if ctx.CheCluster.IsOpenShiftOAuthUserMustBeDeleted() {
|
||||
if done := oou.Delete(ctx); !done {
|
||||
return reconcile.Result{}, false, fmt.Errorf("unable to delete initial OpenShift OAuth user from a cluster")
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
func (oou *OpenShiftOAuthUser) Finalize(ctx *deploy.DeployContext) bool {
|
||||
if util.IsOpenShift4 {
|
||||
return oou.Delete(ctx)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Creates new htpasswd provider with initial user with Che flavor name
|
||||
// if Openshift cluster hasn't got identity providers then does nothing.
|
||||
// It usefull for good first user experience.
|
||||
// User can't use kube:admin or system:admin user in the Openshift oAuth when DevWorkspace engine disabled.
|
||||
// That's why we provide initial user for good first meeting with Eclipse Che.
|
||||
func (oou *OpenShiftOAuthUser) Create(ctx *deploy.DeployContext) (bool, error) {
|
||||
userName := deploy.DefaultCheFlavor(ctx.CheCluster)
|
||||
|
||||
// read existed password from the secret (operator has been restarted case)
|
||||
oAuthUserCredentialsSecret, err := oou.getOpenShiftOAuthUserCredentialsSecret(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if oAuthUserCredentialsSecret != nil {
|
||||
oou.userPassword = string(oAuthUserCredentialsSecret.Data["password"])
|
||||
}
|
||||
|
||||
// create a new secret with user's credentials
|
||||
if oAuthUserCredentialsSecret == nil {
|
||||
initialUserSecretData := map[string][]byte{"user": []byte(userName), "password": []byte(oou.userPassword)}
|
||||
done, err := deploy.SyncSecretToCluster(ctx, OpenShiftOAuthUserCredentialsSecret, OcConfigNamespace, initialUserSecretData)
|
||||
if !done {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
htpasswdSecretExists, _ := deploy.Get(ctx, types.NamespacedName{Name: HtpasswdSecretName, Namespace: OcConfigNamespace}, &corev1.Secret{})
|
||||
if !htpasswdSecretExists {
|
||||
htpasswdFileContent, err := oou.generateHtPasswdUserInfo(userName, oou.userPassword)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
htpasswdFileSecretData := map[string][]byte{"htpasswd": []byte(htpasswdFileContent)}
|
||||
done, err := deploy.SyncSecretToCluster(ctx, HtpasswdSecretName, OcConfigNamespace, htpasswdFileSecretData)
|
||||
if !done {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
oAuth, err := GetOpenshiftOAuth(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := appendIdentityProvider(oAuth, ctx.ClusterAPI.NonCachingClient); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Status.OpenShiftOAuthUserCredentialsSecret != OpenShiftOAuthUserCredentialsSecret {
|
||||
ctx.CheCluster.Status.OpenShiftOAuthUserCredentialsSecret = OpenShiftOAuthUserCredentialsSecret
|
||||
if err := deploy.UpdateCheCRStatus(ctx, "openShiftOAuthUserCredentialsSecret", OpenShiftOAuthUserCredentialsSecret); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := deploy.AppendFinalizer(ctx, OpenshiftOauthUserFinalizerName); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Removes initial user, htpasswd provider, htpasswd secret and Che secret with username and password.
|
||||
func (oou *OpenShiftOAuthUser) Delete(ctx *deploy.DeployContext) bool {
|
||||
done := true
|
||||
|
||||
oAuth, err := GetOpenshiftOAuth(ctx)
|
||||
if err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Failed to get Openshift OAuth, cause: %v", err)
|
||||
}
|
||||
|
||||
userName := deploy.DefaultCheFlavor(ctx.CheCluster)
|
||||
if _, err := deploy.Delete(ctx, types.NamespacedName{Name: userName}, &userv1.User{}); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Failed to delete Openshift user '%s', cause: %v", userName, err)
|
||||
}
|
||||
|
||||
identityName := HtpasswdIdentityProviderName + ":" + userName
|
||||
if _, err := deploy.Delete(ctx, types.NamespacedName{Name: identityName}, &userv1.Identity{}); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Failed to delete identity '%s', cause: %v", identityName, err)
|
||||
}
|
||||
|
||||
if err := deleteIdentityProvider(oAuth, ctx.ClusterAPI.NonCachingClient); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Failed to delete identity provider', cause: %v", err)
|
||||
}
|
||||
|
||||
if _, err = deploy.Delete(ctx, types.NamespacedName{Name: HtpasswdSecretName, Namespace: OcConfigNamespace}, &corev1.Secret{}); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Failed to delete HTpasswd secret '%s', cause: %v", HtpasswdSecretName, err)
|
||||
}
|
||||
|
||||
// legacy secret in the current namespace
|
||||
if _, err = deploy.DeleteNamespacedObject(ctx, OpenShiftOAuthUserCredentialsSecret, &corev1.Secret{}); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Failed to delete legacy Openshift OAuth credentials secret '%s', cause: %v", OpenShiftOAuthUserCredentialsSecret, err)
|
||||
}
|
||||
|
||||
if _, err = deploy.Delete(ctx, types.NamespacedName{Name: OpenShiftOAuthUserCredentialsSecret, Namespace: OcConfigNamespace}, &corev1.Secret{}); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Failed to delete Openshift OAuth credentials secret '%s', cause: %v", OpenShiftOAuthUserCredentialsSecret, err)
|
||||
}
|
||||
|
||||
if err := deploy.DeleteFinalizer(ctx, OpenshiftOauthUserFinalizerName); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Error deleting finalizer: %v", err)
|
||||
}
|
||||
|
||||
ctx.CheCluster.Status.OpenShiftOAuthUserCredentialsSecret = ""
|
||||
if err := deploy.UpdateCheCRStatus(ctx, "openShiftOAuthUserCredentialsSecret", ""); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Filed to update openShiftOAuthUserCredentialsSecret in CR status, cause: %v", err)
|
||||
}
|
||||
|
||||
// set 'openShiftoAuth:nil` to reenable on the following reconcile loop (if possible)
|
||||
ctx.CheCluster.Spec.Auth.InitialOpenShiftOAuthUser = nil
|
||||
ctx.CheCluster.Spec.Auth.OpenShiftoAuth = nil
|
||||
updateFields := map[string]string{
|
||||
"openShiftoAuth": "nil",
|
||||
"initialOpenShiftOAuthUser": "nil",
|
||||
}
|
||||
|
||||
if err := deploy.UpdateCheCRSpecByFields(ctx, updateFields); err != nil {
|
||||
done = false
|
||||
logrus.Errorf("Filed to update OAuth field in CR, cause: %v", err)
|
||||
}
|
||||
|
||||
return done
|
||||
}
|
||||
|
||||
func (oou *OpenShiftOAuthUser) generateHtPasswdUserInfo(userName string, password string) (string, error) {
|
||||
if util.IsTestMode() {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
err := oou.runnable.Run("htpasswd", "-nbB", userName, password)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(oou.runnable.GetStdErr()) > 0 {
|
||||
return "", fmt.Errorf("Failed to generate data for HTPasswd identity provider: %s", oou.runnable.GetStdErr())
|
||||
}
|
||||
return oou.runnable.GetStdOut(), nil
|
||||
}
|
||||
|
||||
// Gets OpenShift user credentials secret from from the secret from:
|
||||
// - openshift-config namespace
|
||||
// - eclipse-che namespace
|
||||
func (oou *OpenShiftOAuthUser) getOpenShiftOAuthUserCredentialsSecret(ctx *deploy.DeployContext) (*corev1.Secret, error) {
|
||||
secret := &corev1.Secret{}
|
||||
|
||||
exists, err := deploy.Get(ctx, types.NamespacedName{Name: OpenShiftOAuthUserCredentialsSecret, Namespace: OcConfigNamespace}, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if exists {
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
exists, err = deploy.GetNamespacedObject(ctx, OpenShiftOAuthUserCredentialsSecret, secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if exists {
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func identityProviderExists(providerName string, oAuth *configv1.OAuth) bool {
|
||||
if len(oAuth.Spec.IdentityProviders) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, identityProvider := range oAuth.Spec.IdentityProviders {
|
||||
if identityProvider.Name == providerName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func appendIdentityProvider(oAuth *configv1.OAuth, runtimeClient client.Client) error {
|
||||
htpasswdProvider := newHtpasswdProvider()
|
||||
if !identityProviderExists(htpasswdProvider.Name, oAuth) {
|
||||
oauthPatch := client.MergeFrom(oAuth.DeepCopy())
|
||||
|
||||
oAuth.Spec.IdentityProviders = append(oAuth.Spec.IdentityProviders, *htpasswdProvider)
|
||||
|
||||
if err := runtimeClient.Patch(context.TODO(), oAuth, oauthPatch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newHtpasswdProvider() *configv1.IdentityProvider {
|
||||
return &configv1.IdentityProvider{
|
||||
Name: HtpasswdIdentityProviderName,
|
||||
MappingMethod: configv1.MappingMethodClaim,
|
||||
IdentityProviderConfig: configv1.IdentityProviderConfig{
|
||||
Type: "HTPasswd",
|
||||
HTPasswd: &configv1.HTPasswdIdentityProvider{
|
||||
FileData: configv1.SecretNameReference{Name: HtpasswdSecretName},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func deleteIdentityProvider(oAuth *configv1.OAuth, runtimeClient client.Client) error {
|
||||
logrus.Info("Delete initial user httpasswd provider from the oAuth")
|
||||
|
||||
oauthPatch := client.MergeFrom(oAuth.DeepCopy())
|
||||
ips := oAuth.Spec.IdentityProviders
|
||||
for i, ip := range ips {
|
||||
if ip.Name == HtpasswdIdentityProviderName {
|
||||
// remove provider from slice
|
||||
oAuth.Spec.IdentityProviders = append(ips[:i], ips[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := runtimeClient.Patch(context.TODO(), oAuth, oauthPatch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 openshiftoauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
oauth_config "github.com/openshift/api/config/v1"
|
||||
userv1 "github.com/openshift/api/user/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
testNamespace = "test-namespace"
|
||||
testUserName = "test"
|
||||
)
|
||||
|
||||
func TestCreateInitialUser(t *testing.T) {
|
||||
checluster := &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "eclipse-che",
|
||||
Namespace: testNamespace,
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CheFlavor: testUserName,
|
||||
},
|
||||
},
|
||||
}
|
||||
oAuth := &oauth_config.OAuth{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "cluster",
|
||||
},
|
||||
Spec: oauth_config.OAuthSpec{IdentityProviders: []oauth_config.IdentityProvider{}},
|
||||
}
|
||||
logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true)))
|
||||
ctx := deploy.GetTestDeployContext(checluster, []runtime.Object{oAuth})
|
||||
|
||||
openShiftOAuthUser := NewOpenShiftOAuthUser()
|
||||
done, err := openShiftOAuthUser.Create(ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, done)
|
||||
|
||||
// Check created objects
|
||||
expectedCheSecret := &corev1.Secret{}
|
||||
err = ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: OpenShiftOAuthUserCredentialsSecret, Namespace: OcConfigNamespace}, expectedCheSecret)
|
||||
assert.Nil(t, err)
|
||||
|
||||
expectedHtpasswsSecret := &corev1.Secret{}
|
||||
err = ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: HtpasswdSecretName, Namespace: OcConfigNamespace}, expectedHtpasswsSecret)
|
||||
assert.Nil(t, err)
|
||||
|
||||
expectedOAuth := &oauth_config.OAuth{}
|
||||
err = ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: "cluster"}, expectedOAuth)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(expectedOAuth.Spec.IdentityProviders), 1)
|
||||
assert.True(t, util.ContainsString(checluster.Finalizers, OpenshiftOauthUserFinalizerName))
|
||||
|
||||
assert.Equal(t, checluster.Status.OpenShiftOAuthUserCredentialsSecret, OpenShiftOAuthUserCredentialsSecret)
|
||||
}
|
||||
|
||||
func TestDeleteInitialUser(t *testing.T) {
|
||||
checluster := &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "eclipse-che",
|
||||
Namespace: testNamespace,
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CheFlavor: testUserName,
|
||||
},
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
OpenShiftOAuthUserCredentialsSecret: "some-secret",
|
||||
},
|
||||
}
|
||||
oAuth := &oauth_config.OAuth{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "cluster",
|
||||
},
|
||||
Spec: oauth_config.OAuthSpec{IdentityProviders: []oauth_config.IdentityProvider{*newHtpasswdProvider()}},
|
||||
}
|
||||
cheSecret := &corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: OpenShiftOAuthUserCredentialsSecret,
|
||||
Namespace: OcConfigNamespace,
|
||||
},
|
||||
}
|
||||
htpasswdSecret := &corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: HtpasswdSecretName,
|
||||
Namespace: OcConfigNamespace,
|
||||
},
|
||||
}
|
||||
userIdentity := &userv1.Identity{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: HtpasswdIdentityProviderName + ":" + testUserName,
|
||||
},
|
||||
}
|
||||
user := &userv1.User{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: testUserName,
|
||||
},
|
||||
}
|
||||
|
||||
logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true)))
|
||||
ctx := deploy.GetTestDeployContext(checluster, []runtime.Object{oAuth, cheSecret, htpasswdSecret, userIdentity, user})
|
||||
|
||||
openShiftOAuthUser := &OpenShiftOAuthUser{}
|
||||
done := openShiftOAuthUser.Delete(ctx)
|
||||
assert.True(t, done)
|
||||
|
||||
expectedCheSecret := &corev1.Secret{}
|
||||
err := ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: OpenShiftOAuthUserCredentialsSecret, Namespace: OcConfigNamespace}, expectedCheSecret)
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
|
||||
expectedHtpasswsSecret := &corev1.Secret{}
|
||||
if err := ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: HtpasswdSecretName, Namespace: OcConfigNamespace}, expectedHtpasswsSecret); !errors.IsNotFound(err) {
|
||||
t.Errorf("Initial user secret should be deleted")
|
||||
}
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
|
||||
expectedUserIdentity := &userv1.Identity{}
|
||||
err = ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: HtpasswdIdentityProviderName + ":" + testUserName}, expectedUserIdentity)
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
|
||||
expectedUser := &userv1.User{}
|
||||
err = ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: testUserName}, expectedUser)
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
|
||||
expectedOAuth := &oauth_config.OAuth{}
|
||||
err = ctx.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: "cluster"}, expectedOAuth)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(expectedOAuth.Spec.IdentityProviders), 0)
|
||||
assert.False(t, util.ContainsString(checluster.Finalizers, OpenshiftOauthUserFinalizerName))
|
||||
assert.Empty(t, checluster.Status.OpenShiftOAuthUserCredentialsSecret)
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 openshiftoauth
|
||||
|
||||
import (
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
oauthv1 "github.com/openshift/api/config/v1"
|
||||
)
|
||||
|
||||
// Gets OpenShift OAuth.
|
||||
func GetOpenshiftOAuth(ctx *deploy.DeployContext) (*oauthv1.OAuth, error) {
|
||||
oAuth := &oauthv1.OAuth{}
|
||||
if done, err := deploy.GetClusterObject(ctx, "cluster", oAuth); !done {
|
||||
return nil, err
|
||||
}
|
||||
return oAuth, nil
|
||||
}
|
||||
|
|
@ -95,18 +95,11 @@ func (p *PluginRegistryReconciler) ExposeEndpoint(ctx *deploy.DeployContext) (st
|
|||
return expose.Expose(
|
||||
ctx,
|
||||
deploy.PluginRegistryName,
|
||||
ctx.CheCluster.Spec.Server.PluginRegistryRoute,
|
||||
ctx.CheCluster.Spec.Server.PluginRegistryIngress,
|
||||
p.createGatewayConfig(ctx))
|
||||
}
|
||||
|
||||
func (p *PluginRegistryReconciler) updateStatus(endpoint string, ctx *deploy.DeployContext) (bool, error) {
|
||||
var pluginRegistryURL string
|
||||
if ctx.CheCluster.Spec.Server.TlsSupport {
|
||||
pluginRegistryURL = "https://" + endpoint
|
||||
} else {
|
||||
pluginRegistryURL = "http://" + endpoint
|
||||
}
|
||||
pluginRegistryURL := "https://" + endpoint
|
||||
|
||||
// append the API version to plugin registry
|
||||
if !strings.HasSuffix(pluginRegistryURL, "/") {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import (
|
|||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -35,7 +34,6 @@ func TestPluginRegistryReconcile(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "plugin-registry", Namespace: "eclipse-che"}, &corev1.Service{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "plugin-registry", Namespace: "eclipse-che"}, &routev1.Route{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "plugin-registry", Namespace: "eclipse-che"}, &corev1.ConfigMap{}))
|
||||
assert.True(t, util.IsObjectExists(ctx.ClusterAPI.Client, types.NamespacedName{Name: "plugin-registry", Namespace: "eclipse-che"}, &appsv1.Deployment{}))
|
||||
assert.NotEmpty(t, ctx.CheCluster.Status.PluginRegistryURL)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
|
|
@ -20,7 +19,6 @@ import (
|
|||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
|
|
@ -52,15 +50,6 @@ func (p *PostgresReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile.Res
|
|||
return reconcile.Result{}, false, err
|
||||
}
|
||||
|
||||
if !ctx.CheCluster.Status.DbProvisoned {
|
||||
if !util.IsTestMode() { // ignore in tests
|
||||
done, err = p.provisionDB(ctx)
|
||||
if !done {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Spec.Database.PostgresVersion == "" {
|
||||
if !util.IsTestMode() { // ignore in tests
|
||||
done, err := p.setDbVersion(ctx)
|
||||
|
|
@ -111,40 +100,6 @@ func (p *PostgresReconciler) syncDeployment(ctx *deploy.DeployContext) (bool, er
|
|||
return deploy.SyncDeploymentSpecToCluster(ctx, specDeployment, deploy.DefaultDeploymentDiffOpts)
|
||||
}
|
||||
|
||||
func (p *PostgresReconciler) provisionDB(ctx *deploy.DeployContext) (bool, error) {
|
||||
identityProviderPostgresPassword := ctx.CheCluster.Spec.Auth.IdentityProviderPostgresPassword
|
||||
identityProviderPostgresSecret := ctx.CheCluster.Spec.Auth.IdentityProviderPostgresSecret
|
||||
if identityProviderPostgresSecret != "" {
|
||||
secret := &corev1.Secret{}
|
||||
exists, err := deploy.GetNamespacedObject(ctx, 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(
|
||||
ctx.CheCluster,
|
||||
deploy.PostgresName,
|
||||
func(cr *orgv1.CheCluster) (string, error) {
|
||||
return getPostgresProvisionCommand(identityProviderPostgresPassword), nil
|
||||
},
|
||||
"create Keycloak DB, user, privileges")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ctx.CheCluster.Status.DbProvisoned = true
|
||||
err = deploy.UpdateCheCRStatus(ctx, "status: provisioned with DB and user", "true")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *PostgresReconciler) setDbVersion(ctx *deploy.DeployContext) (bool, error) {
|
||||
postgresVersion, err := util.K8sclient.ExecIntoPod(
|
||||
ctx.CheCluster,
|
||||
|
|
@ -167,14 +122,3 @@ func (p *PostgresReconciler) setDbVersion(ctx *deploy.DeployContext) (bool, erro
|
|||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func getPostgresProvisionCommand(identityProviderPostgresPassword string) (command string) {
|
||||
command = "OUT=$(psql postgres -tAc \"SELECT 1 FROM pg_roles WHERE rolname='keycloak'\"); " +
|
||||
"if [ $OUT -eq 1 ]; then echo \"DB exists\"; exit 0; fi " +
|
||||
"&& psql -c \"CREATE USER keycloak WITH PASSWORD '" + identityProviderPostgresPassword + "'\" " +
|
||||
"&& psql -c \"CREATE DATABASE keycloak\" " +
|
||||
"&& psql -c \"GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak\" " +
|
||||
"&& psql -c \"ALTER USER ${POSTGRESQL_USER} WITH SUPERUSER\""
|
||||
|
||||
return command
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,23 +35,17 @@ func NewGatewayPermissionsReconciler() *GatewayPermissionsReconciler {
|
|||
}
|
||||
|
||||
func (gp *GatewayPermissionsReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile.Result, bool, error) {
|
||||
if ctx.CheCluster.IsNativeUserModeEnabled() {
|
||||
name := gp.gatewayPermissionsName(ctx.CheCluster)
|
||||
if done, err := deploy.SyncClusterRoleToCluster(ctx, name, gp.getGatewayClusterRoleRules()); !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
name := gp.gatewayPermissionsName(ctx.CheCluster)
|
||||
if done, err := deploy.SyncClusterRoleToCluster(ctx, name, gp.getGatewayClusterRoleRules()); !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
|
||||
if done, err := deploy.SyncClusterRoleBindingToCluster(ctx, name, gateway.GatewayServiceName, name); !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
if done, err := deploy.SyncClusterRoleBindingToCluster(ctx, name, gateway.GatewayServiceName, name); !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
|
||||
if err := deploy.AppendFinalizer(ctx, CheGatewayClusterPermissionsFinalizerName); err != nil {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
} else {
|
||||
if done, err := gp.deleteGatewayPermissions(ctx); !done {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
if err := deploy.AppendFinalizer(ctx, CheGatewayClusterPermissionsFinalizerName); err != nil {
|
||||
return reconcile.Result{Requeue: true}, false, err
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
func TestReconcileWorkspacePermissions(t *testing.T) {
|
||||
|
|
@ -47,9 +46,6 @@ func TestReconcileWorkspacePermissions(t *testing.T) {
|
|||
Server: orgv1.CheClusterSpecServer{
|
||||
WorkspaceNamespaceDefault: "some-test-namespace",
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: pointer.BoolPtr(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -67,9 +63,6 @@ func TestReconcileWorkspacePermissions(t *testing.T) {
|
|||
"CHE_INFRA_KUBERNETES_NAMESPACE_DEFAULT": "some-test-namespace",
|
||||
},
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: pointer.BoolPtr(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ func GetRouteSpec(
|
|||
component string) (*routev1.Route, error) {
|
||||
|
||||
cheFlavor := DefaultCheFlavor(deployContext.CheCluster)
|
||||
tlsSupport := deployContext.CheCluster.Spec.Server.TlsSupport
|
||||
labels := GetLabels(deployContext.CheCluster, component)
|
||||
MergeLabels(labels, routeCustomSettings.Labels)
|
||||
|
||||
|
|
@ -153,26 +152,24 @@ func GetRouteSpec(
|
|||
route.Spec.Host = fmt.Sprintf(HostNameTemplate, route.ObjectMeta.Name, route.ObjectMeta.Namespace, routeCustomSettings.Domain)
|
||||
}
|
||||
|
||||
if tlsSupport {
|
||||
route.Spec.TLS = &routev1.TLSConfig{
|
||||
InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
|
||||
Termination: routev1.TLSTerminationEdge,
|
||||
route.Spec.TLS = &routev1.TLSConfig{
|
||||
InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect,
|
||||
Termination: routev1.TLSTerminationEdge,
|
||||
}
|
||||
|
||||
// for server and dashboard ingresses
|
||||
if (component == cheFlavor || component == cheFlavor+"-dashboard") && deployContext.CheCluster.Spec.Server.CheHostTLSSecret != "" {
|
||||
secret := &corev1.Secret{}
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: deployContext.CheCluster.Namespace,
|
||||
Name: deployContext.CheCluster.Spec.Server.CheHostTLSSecret,
|
||||
}
|
||||
if err := deployContext.ClusterAPI.Client.Get(context.TODO(), namespacedName, secret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// for server and dashboard ingresses
|
||||
if (component == cheFlavor || component == cheFlavor+"-dashboard") && deployContext.CheCluster.Spec.Server.CheHostTLSSecret != "" {
|
||||
secret := &corev1.Secret{}
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: deployContext.CheCluster.Namespace,
|
||||
Name: deployContext.CheCluster.Spec.Server.CheHostTLSSecret,
|
||||
}
|
||||
if err := deployContext.ClusterAPI.Client.Get(context.TODO(), namespacedName, secret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
route.Spec.TLS.Key = string(secret.Data["tls.key"])
|
||||
route.Spec.TLS.Certificate = string(secret.Data["tls.crt"])
|
||||
}
|
||||
route.Spec.TLS.Key = string(secret.Data["tls.key"])
|
||||
route.Spec.TLS.Certificate = string(secret.Data["tls.crt"])
|
||||
}
|
||||
|
||||
return route, nil
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ func TestRouteSpec(t *testing.T) {
|
|||
Name: "che",
|
||||
Weight: &weight,
|
||||
},
|
||||
TLS: &routev1.TLSConfig{Termination: routev1.TLSTerminationEdge, InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect},
|
||||
Port: &routev1.RoutePort{
|
||||
TargetPort: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
|
|
@ -127,6 +128,7 @@ func TestRouteSpec(t *testing.T) {
|
|||
Name: "che",
|
||||
Weight: &weight,
|
||||
},
|
||||
TLS: &routev1.TLSConfig{Termination: routev1.TLSTerminationEdge, InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect},
|
||||
Port: &routev1.RoutePort{
|
||||
TargetPort: intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ package server
|
|||
|
||||
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"
|
||||
networking "k8s.io/api/networking/v1"
|
||||
|
|
@ -60,7 +61,7 @@ func (s *CheHostReconciler) getDefaultCheHost(ctx *deploy.DeployContext) (bool,
|
|||
getComponentName(ctx),
|
||||
"",
|
||||
"/",
|
||||
getServerExposingServiceName(ctx.CheCluster),
|
||||
gateway.GatewayServiceName,
|
||||
8080,
|
||||
ctx.CheCluster.Spec.Server.CheServerRoute,
|
||||
getComponentName(ctx))
|
||||
|
|
@ -97,7 +98,6 @@ func (s *CheHostReconciler) syncCheService(ctx *deploy.DeployContext) (bool, err
|
|||
|
||||
func (s CheHostReconciler) exposeCheEndpoint(ctx *deploy.DeployContext) (bool, error) {
|
||||
cheHost := ""
|
||||
exposedServiceName := getServerExposingServiceName(ctx.CheCluster)
|
||||
|
||||
if !util.IsOpenShift {
|
||||
_, done, err := deploy.SyncIngressToCluster(
|
||||
|
|
@ -105,7 +105,7 @@ func (s CheHostReconciler) exposeCheEndpoint(ctx *deploy.DeployContext) (bool, e
|
|||
getComponentName(ctx),
|
||||
ctx.CheCluster.Spec.Server.CheHost,
|
||||
"",
|
||||
exposedServiceName,
|
||||
gateway.GatewayServiceName,
|
||||
8080,
|
||||
ctx.CheCluster.Spec.Server.CheServerIngress,
|
||||
getComponentName(ctx))
|
||||
|
|
@ -132,7 +132,7 @@ func (s CheHostReconciler) exposeCheEndpoint(ctx *deploy.DeployContext) (bool, e
|
|||
getComponentName(ctx),
|
||||
customHost,
|
||||
"/",
|
||||
exposedServiceName,
|
||||
gateway.GatewayServiceName,
|
||||
8080,
|
||||
ctx.CheCluster.Spec.Server.CheServerRoute,
|
||||
getComponentName(ctx))
|
||||
|
|
|
|||
|
|
@ -13,12 +13,8 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
|
|
@ -31,14 +27,7 @@ func NewDefaultValuesReconciler() *DefaultValuesReconciler {
|
|||
}
|
||||
|
||||
func (p *DefaultValuesReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile.Result, bool, error) {
|
||||
cheFlavor := deploy.DefaultCheFlavor(ctx.CheCluster)
|
||||
cheNamespace := ctx.CheCluster.Namespace
|
||||
if len(ctx.CheCluster.Spec.Server.CheFlavor) < 1 {
|
||||
ctx.CheCluster.Spec.Server.CheFlavor = cheFlavor
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "installation flavor", cheFlavor); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.CheCluster.Spec.Database.ChePostgresSecret) < 1 {
|
||||
if len(ctx.CheCluster.Spec.Database.ChePostgresUser) < 1 || len(ctx.CheCluster.Spec.Database.ChePostgresPassword) < 1 {
|
||||
|
|
@ -66,66 +55,6 @@ func (p *DefaultValuesReconciler) Reconcile(ctx *deploy.DeployContext) (reconcil
|
|||
}
|
||||
}
|
||||
}
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderPostgresSecret) < 1 {
|
||||
keycloakPostgresPassword := util.GeneratePasswd(12)
|
||||
keycloakDeployment := &appsv1.Deployment{}
|
||||
exists, err := deploy.GetNamespacedObject(ctx, deploy.IdentityProviderName, keycloakDeployment)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
if exists {
|
||||
keycloakPostgresPassword = util.GetDeploymentEnv(keycloakDeployment, "DB_PASSWORD")
|
||||
}
|
||||
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderPostgresPassword) < 1 {
|
||||
identityPostgresSecret := deploy.DefaultCheIdentityPostgresSecret()
|
||||
_, err := deploy.SyncSecretToCluster(ctx, identityPostgresSecret, cheNamespace, map[string][]byte{"password": []byte(keycloakPostgresPassword)})
|
||||
if err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
ctx.CheCluster.Spec.Auth.IdentityProviderPostgresSecret = identityPostgresSecret
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "Identity Provider Postgres Secret", identityPostgresSecret); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderSecret) < 1 {
|
||||
keycloakAdminUserName := util.GetValue(ctx.CheCluster.Spec.Auth.IdentityProviderAdminUserName, "admin")
|
||||
keycloakAdminPassword := util.GetValue(ctx.CheCluster.Spec.Auth.IdentityProviderPassword, util.GeneratePasswd(12))
|
||||
|
||||
keycloakDeployment := &appsv1.Deployment{}
|
||||
exists, _ := deploy.GetNamespacedObject(ctx, deploy.IdentityProviderName, keycloakDeployment)
|
||||
if exists {
|
||||
keycloakAdminUserName = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_USERNAME")
|
||||
keycloakAdminPassword = util.GetDeploymentEnv(keycloakDeployment, "SSO_ADMIN_PASSWORD")
|
||||
}
|
||||
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderAdminUserName) < 1 || len(ctx.CheCluster.Spec.Auth.IdentityProviderPassword) < 1 {
|
||||
identityProviderSecret := deploy.DefaultCheIdentitySecret()
|
||||
_, err := deploy.SyncSecretToCluster(ctx, identityProviderSecret, cheNamespace, map[string][]byte{"user": []byte(keycloakAdminUserName), "password": []byte(keycloakAdminPassword)})
|
||||
if err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
ctx.CheCluster.Spec.Auth.IdentityProviderSecret = identityProviderSecret
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "Identity Provider Secret", identityProviderSecret); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
} else {
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderPassword) < 1 {
|
||||
ctx.CheCluster.Spec.Auth.IdentityProviderPassword = keycloakAdminPassword
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "Keycloak admin password", "password hidden"); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderAdminUserName) < 1 {
|
||||
ctx.CheCluster.Spec.Auth.IdentityProviderAdminUserName = keycloakAdminUserName
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "Keycloak admin username", keycloakAdminUserName); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chePostgresDb := util.GetValue(ctx.CheCluster.Spec.Database.ChePostgresDb, "dbche")
|
||||
if len(ctx.CheCluster.Spec.Database.ChePostgresDb) < 1 {
|
||||
|
|
@ -149,24 +78,6 @@ func (p *DefaultValuesReconciler) Reconcile(ctx *deploy.DeployContext) (reconcil
|
|||
}
|
||||
}
|
||||
|
||||
if !ctx.CheCluster.IsNativeUserModeEnabled() {
|
||||
keycloakRealm := util.GetValue(ctx.CheCluster.Spec.Auth.IdentityProviderRealm, cheFlavor)
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderRealm) < 1 {
|
||||
ctx.CheCluster.Spec.Auth.IdentityProviderRealm = keycloakRealm
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "Keycloak realm", keycloakRealm); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
keycloakClientId := util.GetValue(ctx.CheCluster.Spec.Auth.IdentityProviderClientId, cheFlavor+"-public")
|
||||
if len(ctx.CheCluster.Spec.Auth.IdentityProviderClientId) < 1 {
|
||||
ctx.CheCluster.Spec.Auth.IdentityProviderClientId = keycloakClientId
|
||||
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "Keycloak client ID", keycloakClientId); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cheLogLevel := util.GetValue(ctx.CheCluster.Spec.Server.CheLogLevel, deploy.DefaultCheLogLevel)
|
||||
if len(ctx.CheCluster.Spec.Server.CheLogLevel) < 1 {
|
||||
ctx.CheCluster.Spec.Server.CheLogLevel = cheLogLevel
|
||||
|
|
@ -196,76 +107,6 @@ func (p *DefaultValuesReconciler) Reconcile(ctx *deploy.DeployContext) (reconcil
|
|||
}
|
||||
}
|
||||
|
||||
// This is only to correctly manage defaults during the transition
|
||||
// from Upstream 7.0.0 GA to the next
|
||||
// version that should fixed bug https://github.com/eclipse/che/issues/13714
|
||||
// Or for the transition from CRW 1.2 to 2.0
|
||||
|
||||
if ctx.CheCluster.Spec.Storage.PvcJobsImage == deploy.OldDefaultPvcJobsUpstreamImageToDetect ||
|
||||
(deploy.MigratingToCRW2_0(ctx.CheCluster) && ctx.CheCluster.Spec.Storage.PvcJobsImage != "") {
|
||||
ctx.CheCluster.Spec.Storage.PvcJobsImage = ""
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "pvc jobs image", ctx.CheCluster.Spec.Storage.PvcJobsImage); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Spec.Database.PostgresImage == deploy.OldDefaultPostgresUpstreamImageToDetect ||
|
||||
(deploy.MigratingToCRW2_0(ctx.CheCluster) && ctx.CheCluster.Spec.Database.PostgresImage != "") {
|
||||
ctx.CheCluster.Spec.Database.PostgresImage = ""
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "postgres image", ctx.CheCluster.Spec.Database.PostgresImage); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Spec.Auth.IdentityProviderImage == deploy.OldDefaultKeycloakUpstreamImageToDetect ||
|
||||
(deploy.MigratingToCRW2_0(ctx.CheCluster) && ctx.CheCluster.Spec.Auth.IdentityProviderImage != "") {
|
||||
ctx.CheCluster.Spec.Auth.IdentityProviderImage = ""
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "keycloak image", ctx.CheCluster.Spec.Auth.IdentityProviderImage); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if deploy.MigratingToCRW2_0(ctx.CheCluster) &&
|
||||
!ctx.CheCluster.Spec.Server.ExternalPluginRegistry &&
|
||||
ctx.CheCluster.Spec.Server.PluginRegistryUrl == deploy.OldCrwPluginRegistryUrl {
|
||||
ctx.CheCluster.Spec.Server.PluginRegistryUrl = ""
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "plugin registry url", ctx.CheCluster.Spec.Server.PluginRegistryUrl); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if deploy.MigratingToCRW2_0(ctx.CheCluster) &&
|
||||
ctx.CheCluster.Spec.Server.CheImage == deploy.OldDefaultCodeReadyServerImageRepo {
|
||||
ctx.CheCluster.Spec.Server.CheImage = ""
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "che image repo", ctx.CheCluster.Spec.Server.CheImage); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if deploy.MigratingToCRW2_0(ctx.CheCluster) &&
|
||||
ctx.CheCluster.Spec.Server.CheImageTag == deploy.OldDefaultCodeReadyServerImageTag {
|
||||
ctx.CheCluster.Spec.Server.CheImageTag = ""
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "che image tag", ctx.CheCluster.Spec.Server.CheImageTag); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Spec.Server.ServerExposureStrategy == "" && ctx.CheCluster.Spec.K8s.IngressStrategy == "" {
|
||||
strategy := util.GetServerExposureStrategy(ctx.CheCluster)
|
||||
ctx.CheCluster.Spec.Server.ServerExposureStrategy = strategy
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "serverExposureStrategy", strategy); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Spec.DevWorkspace.Enable && ctx.CheCluster.Spec.Auth.NativeUserMode == nil {
|
||||
newNativeUserModeValue := util.NewBoolPointer(true)
|
||||
ctx.CheCluster.Spec.Auth.NativeUserMode = newNativeUserModeValue
|
||||
if err := deploy.UpdateCheCRSpec(ctx, "nativeUserMode", strconv.FormatBool(*newNativeUserModeValue)); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
return reconcile.Result{}, true, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,162 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019-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 server
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
devworkspace "github.com/eclipse-che/che-operator/pkg/deploy/dev-workspace"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEnsureServerExposureStrategy(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
expectedCr *orgv1.CheCluster
|
||||
devWorkspaceEnabled bool
|
||||
initObjects []runtime.Object
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Single Host should be enabled if devWorkspace is enabled",
|
||||
expectedCr: &orgv1.CheCluster{
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "single-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
devWorkspaceEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "Multi Host should be enabled if devWorkspace is not enabled",
|
||||
expectedCr: &orgv1.CheCluster{
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
ServerExposureStrategy: "multi-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
devWorkspaceEnabled: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
checluster := &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "eclipse-che",
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
}
|
||||
|
||||
checluster.Spec.DevWorkspace.Enable = testCase.devWorkspaceEnabled
|
||||
ctx := deploy.GetTestDeployContext(checluster, []runtime.Object{})
|
||||
|
||||
defaults := NewDefaultValuesReconciler()
|
||||
_, done, err := defaults.Reconcile(ctx)
|
||||
assert.True(t, done)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, testCase.expectedCr.Spec.Server.ServerExposureStrategy, ctx.CheCluster.Spec.Server.ServerExposureStrategy)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeUserModeEnabled(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
initObjects []runtime.Object
|
||||
isOpenshift bool
|
||||
devworkspaceEnabled bool
|
||||
initialNativeUserValue *bool
|
||||
expectedNativeUserValue *bool
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "che-operator should use nativeUserMode when devworkspaces on openshift and no initial value in CR for nativeUserMode",
|
||||
isOpenshift: true,
|
||||
devworkspaceEnabled: true,
|
||||
initialNativeUserValue: nil,
|
||||
expectedNativeUserValue: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should use nativeUserMode value from initial CR",
|
||||
isOpenshift: true,
|
||||
devworkspaceEnabled: true,
|
||||
initialNativeUserValue: pointer.BoolPtr(false),
|
||||
expectedNativeUserValue: pointer.BoolPtr(false),
|
||||
},
|
||||
{
|
||||
name: "che-operator should use nativeUserMode value from initial CR",
|
||||
isOpenshift: true,
|
||||
devworkspaceEnabled: true,
|
||||
initialNativeUserValue: pointer.BoolPtr(true),
|
||||
expectedNativeUserValue: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator should use nativeUserMode when devworkspaces on kubernetes and no initial value in CR for nativeUserMode",
|
||||
isOpenshift: false,
|
||||
devworkspaceEnabled: true,
|
||||
initialNativeUserValue: nil,
|
||||
expectedNativeUserValue: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
name: "che-operator not modify nativeUserMode when devworkspace not enabled",
|
||||
isOpenshift: true,
|
||||
devworkspaceEnabled: false,
|
||||
initialNativeUserValue: nil,
|
||||
expectedNativeUserValue: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true)))
|
||||
|
||||
checluster := &orgv1.CheCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "eclipse-che",
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
}
|
||||
|
||||
// reread templates (workaround after setting IsOpenShift value)
|
||||
util.IsOpenShift = testCase.isOpenshift
|
||||
devworkspace.DevWorkspaceTemplates = devworkspace.DevWorkspaceTemplatesPath()
|
||||
devworkspace.DevWorkspaceIssuerFile = devworkspace.DevWorkspaceTemplates + "/devworkspace-controller-selfsigned-issuer.Issuer.yaml"
|
||||
devworkspace.DevWorkspaceCertificateFile = devworkspace.DevWorkspaceTemplates + "/devworkspace-controller-serving-cert.Certificate.yaml"
|
||||
|
||||
checluster.Spec.DevWorkspace.Enable = testCase.devworkspaceEnabled
|
||||
checluster.Spec.Auth.NativeUserMode = testCase.initialNativeUserValue
|
||||
ctx := deploy.GetTestDeployContext(checluster, []runtime.Object{})
|
||||
|
||||
defaults := NewDefaultValuesReconciler()
|
||||
_, done, err := defaults.Reconcile(ctx)
|
||||
assert.True(t, done)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, testCase.expectedNativeUserValue, ctx.CheCluster.Spec.Auth.NativeUserMode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -64,8 +64,6 @@ type CheConfigMap struct {
|
|||
CheLogLevel string `json:"CHE_LOG_LEVEL"`
|
||||
IdentityProviderUrl string `json:"CHE_OIDC_AUTH__SERVER__URL,omitempty"`
|
||||
IdentityProviderInternalURL string `json:"CHE_OIDC_AUTH__INTERNAL__SERVER__URL,omitempty"`
|
||||
KeycloakRealm string `json:"CHE_KEYCLOAK_REALM,omitempty"`
|
||||
KeycloakClientId string `json:"CHE_KEYCLOAK_CLIENT__ID,omitempty"`
|
||||
OpenShiftIdentityProvider string `json:"CHE_INFRA_OPENSHIFT_OAUTH__IDENTITY__PROVIDER"`
|
||||
JavaOpts string `json:"JAVA_OPTS"`
|
||||
WorkspaceJavaOpts string `json:"CHE_WORKSPACE_JAVA__OPTIONS"`
|
||||
|
|
@ -95,37 +93,18 @@ func (s *CheServerReconciler) getCheConfigMapData(ctx *deploy.DeployContext) (ch
|
|||
cheHost := ctx.CheCluster.Spec.Server.CheHost
|
||||
identityProviderURL := ctx.CheCluster.Spec.Auth.IdentityProviderURL
|
||||
|
||||
// Adds `/auth` for external identity providers.
|
||||
// If identity provide is deployed by operator then `/auth` is already added.
|
||||
if !ctx.CheCluster.IsNativeUserModeEnabled() &&
|
||||
ctx.CheCluster.Spec.Auth.ExternalIdentityProvider &&
|
||||
!strings.HasSuffix(identityProviderURL, "/auth") {
|
||||
if strings.HasSuffix(identityProviderURL, "/") {
|
||||
identityProviderURL = identityProviderURL + "auth"
|
||||
} else {
|
||||
identityProviderURL = identityProviderURL + "/auth"
|
||||
}
|
||||
}
|
||||
|
||||
cheFlavor := deploy.DefaultCheFlavor(ctx.CheCluster)
|
||||
infra := "kubernetes"
|
||||
if util.IsOpenShift {
|
||||
infra = "openshift"
|
||||
}
|
||||
tls := "false"
|
||||
openShiftIdentityProviderId := "NULL"
|
||||
if util.IsOpenShift && ctx.CheCluster.IsOpenShiftOAuthEnabled() {
|
||||
if util.IsOpenShift {
|
||||
openShiftIdentityProviderId = "openshift-v3"
|
||||
if util.IsOpenShift4 {
|
||||
openShiftIdentityProviderId = "openshift-v4"
|
||||
}
|
||||
}
|
||||
tlsSupport := ctx.CheCluster.Spec.Server.TlsSupport
|
||||
protocol := "http"
|
||||
if tlsSupport {
|
||||
protocol = "https"
|
||||
tls = "true"
|
||||
}
|
||||
|
||||
proxyJavaOpts := ""
|
||||
cheWorkspaceNoProxy := ctx.Proxy.NoProxy
|
||||
|
|
@ -158,9 +137,6 @@ func (s *CheServerReconciler) getCheConfigMapData(ctx *deploy.DeployContext) (ch
|
|||
chePostgresHostName := util.GetValue(ctx.CheCluster.Spec.Database.ChePostgresHostName, deploy.DefaultChePostgresHostName)
|
||||
chePostgresPort := util.GetValue(ctx.CheCluster.Spec.Database.ChePostgresPort, deploy.DefaultChePostgresPort)
|
||||
chePostgresDb := util.GetValue(ctx.CheCluster.Spec.Database.ChePostgresDb, deploy.DefaultChePostgresDb)
|
||||
keycloakRealm := util.GetValue(ctx.CheCluster.Spec.Auth.IdentityProviderRealm, cheFlavor)
|
||||
keycloakClientId := util.GetValue(ctx.CheCluster.Spec.Auth.IdentityProviderClientId, cheFlavor+"-public")
|
||||
ingressStrategy := util.GetServerExposureStrategy(ctx.CheCluster)
|
||||
ingressClass := util.GetValue(ctx.CheCluster.Spec.K8s.IngressClass, deploy.DefaultIngressClass)
|
||||
|
||||
// grab first the devfile registry url which is deployed by operator
|
||||
|
|
@ -182,45 +158,26 @@ func (s *CheServerReconciler) getCheConfigMapData(ctx *deploy.DeployContext) (ch
|
|||
cheDebug := util.GetValue(ctx.CheCluster.Spec.Server.CheDebug, deploy.DefaultCheDebug)
|
||||
cheMetrics := strconv.FormatBool(ctx.CheCluster.Spec.Metrics.Enable)
|
||||
cheLabels := util.MapToKeyValuePairs(deploy.GetLabels(ctx.CheCluster, deploy.DefaultCheFlavor(ctx.CheCluster)))
|
||||
workspaceExposure := deploy.GetSingleHostExposureType(ctx.CheCluster)
|
||||
singleHostGatewayConfigMapLabels := labels.FormatLabels(util.GetMapValue(ctx.CheCluster.Spec.Server.SingleHostGatewayConfigMapLabels, deploy.DefaultSingleHostGatewayConfigMapLabels))
|
||||
workspaceNamespaceDefault := util.GetWorkspaceNamespaceDefault(ctx.CheCluster)
|
||||
workspaceNamespaceDefault := deploy.GetWorkspaceNamespaceDefault(ctx.CheCluster)
|
||||
|
||||
cheAPI := protocol + "://" + cheHost + "/api"
|
||||
var keycloakInternalURL, pluginRegistryInternalURL, devfileRegistryInternalURL, cheInternalAPI, webSocketInternalEndpoint string
|
||||
|
||||
if !ctx.CheCluster.IsNativeUserModeEnabled() &&
|
||||
ctx.CheCluster.IsInternalClusterSVCNamesEnabled() &&
|
||||
!ctx.CheCluster.Spec.Auth.ExternalIdentityProvider {
|
||||
keycloakInternalURL = fmt.Sprintf("%s://%s.%s.svc:8080/auth", "http", deploy.IdentityProviderName, ctx.CheCluster.Namespace)
|
||||
}
|
||||
cheAPI := "https://" + cheHost + "/api"
|
||||
var pluginRegistryInternalURL, devfileRegistryInternalURL string
|
||||
|
||||
// If there is a devfile registry deployed by operator
|
||||
if ctx.CheCluster.IsInternalClusterSVCNamesEnabled() && !ctx.CheCluster.Spec.Server.ExternalDevfileRegistry {
|
||||
if !ctx.CheCluster.Spec.Server.ExternalDevfileRegistry {
|
||||
devfileRegistryInternalURL = fmt.Sprintf("http://%s.%s.svc:8080", deploy.DevfileRegistryName, ctx.CheCluster.Namespace)
|
||||
}
|
||||
|
||||
if ctx.CheCluster.IsInternalClusterSVCNamesEnabled() && !ctx.CheCluster.Spec.Server.ExternalPluginRegistry {
|
||||
if !ctx.CheCluster.Spec.Server.ExternalPluginRegistry {
|
||||
pluginRegistryInternalURL = fmt.Sprintf("http://%s.%s.svc:8080/v3", deploy.PluginRegistryName, ctx.CheCluster.Namespace)
|
||||
}
|
||||
|
||||
if ctx.CheCluster.IsInternalClusterSVCNamesEnabled() {
|
||||
cheInternalAPI = fmt.Sprintf("http://%s.%s.svc:8080/api", deploy.CheServiceName, ctx.CheCluster.Namespace)
|
||||
webSocketInternalEndpoint = fmt.Sprintf("ws://%s.%s.svc:8080/api/websocket", deploy.CheServiceName, ctx.CheCluster.Namespace)
|
||||
}
|
||||
|
||||
wsprotocol := "ws"
|
||||
if tlsSupport {
|
||||
wsprotocol = "wss"
|
||||
}
|
||||
webSocketEndpoint := wsprotocol + "://" + cheHost + "/api/websocket"
|
||||
|
||||
cheWorkspaceServiceAccount := "che-workspace"
|
||||
cheUserClusterRoleNames := "NULL"
|
||||
if ctx.CheCluster.IsNativeUserModeEnabled() {
|
||||
cheWorkspaceServiceAccount = "NULL"
|
||||
cheUserClusterRoleNames = fmt.Sprintf("%s-cheworkspaces-clusterrole, %s-cheworkspaces-devworkspace-clusterrole", ctx.CheCluster.Namespace, ctx.CheCluster.Namespace)
|
||||
}
|
||||
cheInternalAPI := fmt.Sprintf("http://%s.%s.svc:8080/api", deploy.CheServiceName, ctx.CheCluster.Namespace)
|
||||
webSocketInternalEndpoint := fmt.Sprintf("ws://%s.%s.svc:8080/api/websocket", deploy.CheServiceName, ctx.CheCluster.Namespace)
|
||||
webSocketEndpoint := "wss://" + cheHost + "/api/websocket"
|
||||
cheWorkspaceServiceAccount := "NULL"
|
||||
cheUserClusterRoleNames := fmt.Sprintf("%s-cheworkspaces-clusterrole, %s-cheworkspaces-devworkspace-clusterrole", ctx.CheCluster.Namespace, ctx.CheCluster.Namespace)
|
||||
|
||||
data := &CheConfigMap{
|
||||
CheMultiUser: "true",
|
||||
|
|
@ -240,8 +197,8 @@ func (s *CheServerReconciler) getCheConfigMapData(ctx *deploy.DeployContext) (ch
|
|||
WorkspacePvcStorageClassName: workspacePvcStorageClassName,
|
||||
PvcJobsImage: pvcJobsImage,
|
||||
PreCreateSubPaths: preCreateSubPaths,
|
||||
TlsSupport: tls,
|
||||
K8STrustCerts: tls,
|
||||
TlsSupport: "true",
|
||||
K8STrustCerts: "true",
|
||||
CheLogLevel: cheLogLevel,
|
||||
OpenShiftIdentityProvider: openShiftIdentityProviderId,
|
||||
JavaOpts: deploy.DefaultJavaOpts + " " + proxyJavaOpts,
|
||||
|
|
@ -261,16 +218,13 @@ func (s *CheServerReconciler) getCheConfigMapData(ctx *deploy.DeployContext) (ch
|
|||
CheJGroupsKubernetesLabels: cheLabels,
|
||||
CheMetricsEnabled: cheMetrics,
|
||||
CheTrustedCABundlesConfigMap: deploytls.CheAllCACertsConfigMapName,
|
||||
ServerStrategy: ingressStrategy,
|
||||
WorkspaceExposure: workspaceExposure,
|
||||
ServerStrategy: deploy.ServerExposureStrategy,
|
||||
WorkspaceExposure: deploy.GatewaySingleHostExposureType,
|
||||
SingleHostGatewayConfigMapLabels: singleHostGatewayConfigMapLabels,
|
||||
CheDevWorkspacesEnabled: strconv.FormatBool(ctx.CheCluster.Spec.DevWorkspace.Enable),
|
||||
CheDevWorkspacesEnabled: strconv.FormatBool(true),
|
||||
}
|
||||
|
||||
data.IdentityProviderUrl = identityProviderURL
|
||||
data.IdentityProviderInternalURL = keycloakInternalURL
|
||||
data.KeycloakRealm = keycloakRealm
|
||||
data.KeycloakClientId = keycloakClientId
|
||||
data.DatabaseURL = "jdbc:postgresql://" + chePostgresHostName + ":" + chePostgresPort + "/" + chePostgresDb
|
||||
if len(ctx.CheCluster.Spec.Database.ChePostgresSecret) < 1 {
|
||||
data.DbUserName = ctx.CheCluster.Spec.Database.ChePostgresUser
|
||||
|
|
@ -294,10 +248,7 @@ func (s *CheServerReconciler) getCheConfigMapData(ctx *deploy.DeployContext) (ch
|
|||
"CHE_INFRA_KUBERNETES_INGRESS_ANNOTATIONS__JSON": "{\"kubernetes.io/ingress.class\": " + ingressClass + ", \"nginx.ingress.kubernetes.io/rewrite-target\": \"/$1\",\"nginx.ingress.kubernetes.io/ssl-redirect\": " + tls + ",\"nginx.ingress.kubernetes.io/proxy-connect-timeout\": \"3600\",\"nginx.ingress.kubernetes.io/proxy-read-timeout\": \"3600\"}",
|
||||
"CHE_INFRA_KUBERNETES_INGRESS_PATH__TRANSFORM": "%s(.*)",
|
||||
}
|
||||
|
||||
if ctx.CheCluster.Spec.DevWorkspace.Enable {
|
||||
k8sCheEnv["CHE_INFRA_KUBERNETES_ENABLE__UNSUPPORTED__K8S"] = "true"
|
||||
}
|
||||
k8sCheEnv["CHE_INFRA_KUBERNETES_ENABLE__UNSUPPORTED__K8S"] = "true"
|
||||
|
||||
// Add TLS key and server certificate to properties since user workspaces is created in another
|
||||
// than Che server namespace, from where the Che TLS secret is not accessable
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import (
|
|||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
|
|
@ -47,15 +46,11 @@ func TestNewCheConfigMap(t *testing.T) {
|
|||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CheHost: "myhostname.com",
|
||||
TlsSupport: true,
|
||||
CheHost: "myhostname.com",
|
||||
CustomCheProperties: map[string]string{
|
||||
"CHE_WORKSPACE_NO_PROXY": "myproxy.myhostname.com",
|
||||
},
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
|
|
@ -159,7 +154,7 @@ func TestConfigMap(t *testing.T) {
|
|||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_WEBSOCKET_ENDPOINT": "ws://che-host/api/websocket",
|
||||
"CHE_WEBSOCKET_ENDPOINT": "wss://che-host/api/websocket",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -188,33 +183,12 @@ func TestConfigMap(t *testing.T) {
|
|||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
CheHost: "che-host",
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
CheHost: "che-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_WEBSOCKET_ENDPOINT": "ws://che-host/api/websocket",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Kubernetes strategy should be set correctly",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
K8s: orgv1.CheClusterSpecK8SOnly{
|
||||
IngressStrategy: "single-host",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_INFRA_KUBERNETES_SERVER__STRATEGY": "single-host",
|
||||
"CHE_WEBSOCKET_ENDPOINT": "wss://che-host/api/websocket",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -418,9 +392,8 @@ func TestShouldSetUpCorrectlyDevfileRegistryURL(t *testing.T) {
|
|||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
ExternalDevfileRegistry: true,
|
||||
DevfileRegistryUrl: "http://devfile-registry.external.1",
|
||||
ExternalDevfileRegistry: true,
|
||||
DevfileRegistryUrl: "http://devfile-registry.external.1",
|
||||
ExternalDevfileRegistries: []orgv1.ExternalDevfileRegistries{
|
||||
{Url: "http://devfile-registry.external.2"},
|
||||
},
|
||||
|
|
@ -432,31 +405,6 @@ func TestShouldSetUpCorrectlyDevfileRegistryURL(t *testing.T) {
|
|||
"CHE_WORKSPACE_DEVFILE__REGISTRY__INTERNAL__URL": "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test devfile registry urls #4",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
ExternalDevfileRegistry: false,
|
||||
},
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
DevfileRegistryURL: "http://devfile-registry.internal",
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_WORKSPACE_DEVFILE__REGISTRY__INTERNAL__URL": "",
|
||||
"CHE_WORKSPACE_DEVFILE__REGISTRY__URL": "http://devfile-registry.internal",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test devfile registry urls #5",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
|
|
@ -481,35 +429,6 @@ func TestShouldSetUpCorrectlyDevfileRegistryURL(t *testing.T) {
|
|||
"CHE_WORKSPACE_DEVFILE__REGISTRY__URL": "http://devfile-registry.internal",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test devfile registry urls #6",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
ExternalDevfileRegistry: false,
|
||||
DevfileRegistryUrl: "http://devfile-registry.external.1",
|
||||
ExternalDevfileRegistries: []orgv1.ExternalDevfileRegistries{
|
||||
{Url: "http://devfile-registry.external.2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
DevfileRegistryURL: "http://devfile-registry.internal",
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_WORKSPACE_DEVFILE__REGISTRY__INTERNAL__URL": "",
|
||||
"CHE_WORKSPACE_DEVFILE__REGISTRY__URL": "http://devfile-registry.internal http://devfile-registry.external.1 http://devfile-registry.external.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test devfile registry urls #7",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
|
|
@ -579,9 +498,6 @@ func TestShouldSetUpCorrectlyInternalPluginRegistryServiceURL(t *testing.T) {
|
|||
Server: orgv1.CheClusterSpecServer{
|
||||
ExternalPluginRegistry: true,
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
PluginRegistryURL: "http://external-plugin-registry",
|
||||
|
|
@ -593,60 +509,6 @@ func TestShouldSetUpCorrectlyInternalPluginRegistryServiceURL(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Test CHE_WORKSPACE_PLUGIN__REGISTRY__INTERNAL__URL #2",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
ExternalPluginRegistry: true,
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
PluginRegistryURL: "http://external-plugin-registry",
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_WORKSPACE_PLUGIN__REGISTRY__INTERNAL__URL": "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test CHE_WORKSPACE_PLUGIN__REGISTRY__INTERNAL__URL #3",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
ExternalPluginRegistry: false,
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
PluginRegistryURL: "http://plugin-registry/v3",
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_WORKSPACE_PLUGIN__REGISTRY__INTERNAL__URL": "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test CHE_WORKSPACE_PLUGIN__REGISTRY__INTERNAL__URL #4",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
|
|
@ -659,9 +521,6 @@ func TestShouldSetUpCorrectlyInternalPluginRegistryServiceURL(t *testing.T) {
|
|||
Server: orgv1.CheClusterSpecServer{
|
||||
ExternalPluginRegistry: false,
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
Status: orgv1.CheClusterStatus{
|
||||
PluginRegistryURL: "http://external-plugin-registry",
|
||||
|
|
@ -698,30 +557,6 @@ func TestShouldSetUpCorrectlyInternalCheServerURL(t *testing.T) {
|
|||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Should be an empty when internal network is disabled",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
CheHost: "che-host",
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_API_INTERNAL": "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should use internal che-server url, when internal network is enabled",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
|
|
@ -736,9 +571,6 @@ func TestShouldSetUpCorrectlyInternalCheServerURL(t *testing.T) {
|
|||
Server: orgv1.CheClusterSpecServer{
|
||||
CheHost: "http://che-host",
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
|
|
@ -760,154 +592,3 @@ func TestShouldSetUpCorrectlyInternalCheServerURL(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldSetUpCorrectlyInternalIdentityProviderServiceURL(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
isOpenShift bool
|
||||
isOpenShift4 bool
|
||||
initObjects []runtime.Object
|
||||
cheCluster *orgv1.CheCluster
|
||||
expectedData map[string]string
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "Should be an empty when enabled 'external' public identity provider url and internal network is enabled #1",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
ExternalIdentityProvider: true,
|
||||
IdentityProviderURL: "http://external-keycloak",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_OIDC_AUTH__INTERNAL__SERVER__URL": "",
|
||||
"CHE_OIDC_AUTH__SERVER__URL": "http://external-keycloak/auth",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should be an empty when enabled 'external' public identity provider url and internal network is enabled #2",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
ExternalIdentityProvider: true,
|
||||
IdentityProviderURL: "http://external-keycloak/auth",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_OIDC_AUTH__INTERNAL__SERVER__URL": "",
|
||||
"CHE_OIDC_AUTH__SERVER__URL": "http://external-keycloak/auth",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should be and empty when enabled 'external' public identity provider url and internal network is disabled",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
ExternalIdentityProvider: true,
|
||||
IdentityProviderURL: "http://external-keycloak",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_OIDC_AUTH__INTERNAL__SERVER__URL": "",
|
||||
"CHE_OIDC_AUTH__SERVER__URL": "http://external-keycloak/auth",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should be an empty when internal network is disabled",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
DisableInternalClusterSVCNames: pointer.BoolPtr(true),
|
||||
},
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
ExternalIdentityProvider: false,
|
||||
IdentityProviderURL: "http://keycloak/auth",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_OIDC_AUTH__INTERNAL__SERVER__URL": "",
|
||||
"CHE_OIDC_AUTH__SERVER__URL": "http://keycloak/auth",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should use internal identity provider url, when internal network is enabled",
|
||||
cheCluster: &orgv1.CheCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CheCluster",
|
||||
APIVersion: "org.eclipse.che/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Auth: orgv1.CheClusterSpecAuth{
|
||||
OpenShiftoAuth: util.NewBoolPointer(false),
|
||||
ExternalIdentityProvider: false,
|
||||
IdentityProviderURL: "http://keycloak/auth",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedData: map[string]string{
|
||||
"CHE_OIDC_AUTH__INTERNAL__SERVER__URL": "http://keycloak.eclipse-che.svc:8080/auth",
|
||||
"CHE_OIDC_AUTH__SERVER__URL": "http://keycloak/auth",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
util.IsOpenShift = testCase.isOpenShift
|
||||
util.IsOpenShift4 = testCase.isOpenShift4
|
||||
ctx := deploy.GetTestDeployContext(testCase.cheCluster, []runtime.Object{})
|
||||
|
||||
server := NewCheServerReconciler()
|
||||
actualData, err := server.getCheConfigMapData(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating ConfigMap data: %v", err)
|
||||
}
|
||||
|
||||
util.ValidateContainData(actualData, testCase.expectedData, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
identityprovider "github.com/eclipse-che/che-operator/pkg/deploy/identity-provider"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/postgres"
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/tls"
|
||||
|
||||
|
|
@ -112,42 +111,6 @@ func (s CheServerReconciler) getDeploymentSpec(ctx *deploy.DeployContext) (*apps
|
|||
cheEnv = append(cheEnv, selfSignedCertEnv)
|
||||
cheEnv = append(cheEnv, gitSelfSignedCertEnv)
|
||||
cheEnv = append(cheEnv, gitSelfSignedCertHostEnv)
|
||||
|
||||
identityProviderSecret := ctx.CheCluster.Spec.Auth.IdentityProviderSecret
|
||||
if len(identityProviderSecret) > 0 {
|
||||
cheEnv = append(cheEnv, corev1.EnvVar{
|
||||
Name: "CHE_KEYCLOAK_ADMIN__PASSWORD",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "password",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
corev1.EnvVar{
|
||||
Name: "CHE_KEYCLOAK_ADMIN__USERNAME",
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
Key: "user",
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: identityProviderSecret,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
cheEnv = append(cheEnv, corev1.EnvVar{
|
||||
Name: "CHE_KEYCLOAK_ADMIN__PASSWORD",
|
||||
Value: ctx.CheCluster.Spec.Auth.IdentityProviderPassword,
|
||||
},
|
||||
corev1.EnvVar{
|
||||
Name: "CHE_KEYCLOAK_ADMIN__USERNAME",
|
||||
Value: ctx.CheCluster.Spec.Auth.IdentityProviderAdminUserName,
|
||||
})
|
||||
}
|
||||
|
||||
cheEnv = append(cheEnv,
|
||||
corev1.EnvVar{
|
||||
Name: "CM_REVISION",
|
||||
|
|
@ -160,13 +123,10 @@ func (s CheServerReconciler) getDeploymentSpec(ctx *deploy.DeployContext) (*apps
|
|||
APIVersion: "v1",
|
||||
FieldPath: "metadata.namespace"}},
|
||||
})
|
||||
|
||||
if ctx.CheCluster.IsNativeUserModeEnabled() {
|
||||
cheEnv = append(cheEnv, corev1.EnvVar{
|
||||
Name: "CHE_AUTH_NATIVEUSER",
|
||||
Value: "true",
|
||||
})
|
||||
}
|
||||
cheEnv = append(cheEnv, corev1.EnvVar{
|
||||
Name: "CHE_AUTH_NATIVEUSER",
|
||||
Value: "true",
|
||||
})
|
||||
|
||||
cheImageAndTag := GetFullCheServerImageLink(ctx.CheCluster)
|
||||
pullPolicy := corev1.PullPolicy(util.GetValue(string(ctx.CheCluster.Spec.Server.CheImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(cheImageAndTag)))
|
||||
|
|
@ -368,14 +328,6 @@ func (s CheServerReconciler) getDeploymentSpec(ctx *deploy.DeployContext) (*apps
|
|||
}
|
||||
deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers, *waitForPostgresInitContainer)
|
||||
}
|
||||
|
||||
if !ctx.CheCluster.Spec.Auth.ExternalIdentityProvider {
|
||||
waitForKeycloakInitContainer, err := identityprovider.GetWaitForKeycloakInitContainer(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers, *waitForKeycloakInitContainer)
|
||||
}
|
||||
}
|
||||
|
||||
return deployment, nil
|
||||
|
|
|
|||
|
|
@ -36,11 +36,6 @@ func TestReconcile(t *testing.T) {
|
|||
Namespace: "eclipse-che",
|
||||
Name: os.Getenv("CHE_FLAVOR"),
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
TlsSupport: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
util.IsOpenShift = true
|
||||
|
|
@ -70,11 +65,6 @@ func TestSyncLegacyConfigMap(t *testing.T) {
|
|||
Namespace: "eclipse-che",
|
||||
Name: "eclipse-che",
|
||||
},
|
||||
Spec: orgv1.CheClusterSpec{
|
||||
Server: orgv1.CheClusterSpecServer{
|
||||
TlsSupport: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
ctx := deploy.GetTestDeployContext(cheCluster, []runtime.Object{})
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@ package server
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
orgv1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"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"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
|
|
@ -25,13 +22,6 @@ func getComponentName(ctx *deploy.DeployContext) string {
|
|||
return deploy.DefaultCheFlavor(ctx.CheCluster)
|
||||
}
|
||||
|
||||
func getServerExposingServiceName(cr *orgv1.CheCluster) string {
|
||||
if util.GetServerExposureStrategy(cr) == "single-host" && deploy.GetSingleHostExposureType(cr) == deploy.GatewaySingleHostExposureType {
|
||||
return gateway.GatewayServiceName
|
||||
}
|
||||
return deploy.CheServiceName
|
||||
}
|
||||
|
||||
func getOAuthConfig(ctx *deploy.DeployContext, oauthProvider string) (*corev1.Secret, error) {
|
||||
secrets, err := deploy.GetSecrets(ctx, map[string]string{
|
||||
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ package tls
|
|||
import (
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy"
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
|
|
@ -30,42 +29,23 @@ func NewTlsSecretReconciler() *TlsSecretReconciler {
|
|||
func (t *TlsSecretReconciler) Reconcile(ctx *deploy.DeployContext) (reconcile.Result, bool, error) {
|
||||
if util.IsOpenShift {
|
||||
// create a secret with router tls cert when on OpenShift infra and router is configured with a self signed certificate
|
||||
if ctx.IsSelfSignedCertificate ||
|
||||
// To use Openshift v4 OAuth, the OAuth endpoints are served from a namespace
|
||||
// and NOT from the Openshift API Master URL (as in v3)
|
||||
// So we also need the self-signed certificate to access them (same as the Che server)
|
||||
(util.IsOpenShift4 && ctx.CheCluster.IsOpenShiftOAuthEnabled() && !ctx.CheCluster.Spec.Server.TlsSupport) {
|
||||
if ctx.IsSelfSignedCertificate {
|
||||
if err := CreateTLSSecretFromEndpoint(ctx, "", deploy.CheTLSSelfSignedCertificateSecretName); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
if util.IsOpenShift && ctx.CheCluster.IsOpenShiftOAuthEnabled() {
|
||||
// create a secret with OpenShift API crt to be added to keystore that RH SSO will consume
|
||||
apiUrl, apiInternalUrl, err := util.GetOpenShiftAPIUrls()
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to get OpenShift cluster public hostname. A secret with API crt will not be created and consumed by RH-SSO/Keycloak")
|
||||
} else {
|
||||
baseURL := map[bool]string{true: apiInternalUrl, false: apiUrl}[apiInternalUrl != ""]
|
||||
if err := CreateTLSSecretFromEndpoint(ctx, baseURL, "openshift-api-crt"); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle Che TLS certificates on Kubernetes infrastructure
|
||||
if ctx.CheCluster.Spec.Server.TlsSupport {
|
||||
if ctx.CheCluster.Spec.K8s.TlsSecretName != "" {
|
||||
// Self-signed certificate should be created to secure Che ingresses
|
||||
result, err := K8sHandleCheTLSSecrets(ctx)
|
||||
if result.Requeue || result.RequeueAfter > 0 {
|
||||
return result, false, err
|
||||
}
|
||||
} else if ctx.IsSelfSignedCertificate {
|
||||
// Use default self-signed ingress certificate
|
||||
if err := CreateTLSSecretFromEndpoint(ctx, "", deploy.CheTLSSelfSignedCertificateSecretName); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
if ctx.CheCluster.Spec.K8s.TlsSecretName != "" {
|
||||
// Self-signed certificate should be created to secure Che ingresses
|
||||
result, err := K8sHandleCheTLSSecrets(ctx)
|
||||
if result.Requeue || result.RequeueAfter > 0 {
|
||||
return result, false, err
|
||||
}
|
||||
} else if ctx.IsSelfSignedCertificate {
|
||||
// Use default self-signed ingress certificate
|
||||
if err := CreateTLSSecretFromEndpoint(ctx, "", deploy.CheTLSSelfSignedCertificateSecretName); err != nil {
|
||||
return reconcile.Result{}, false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
142
pkg/util/util.go
142
pkg/util/util.go
|
|
@ -15,14 +15,10 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
|
@ -199,23 +195,6 @@ func MergeMaps(first map[string]string, second map[string]string) map[string]str
|
|||
return ret
|
||||
}
|
||||
|
||||
func GetServerExposureStrategy(cheCluster *orgv1.CheCluster) string {
|
||||
if cheCluster.Spec.Server.ServerExposureStrategy != "" {
|
||||
return cheCluster.Spec.Server.ServerExposureStrategy
|
||||
}
|
||||
|
||||
if !IsOpenShift && cheCluster.Spec.K8s.IngressStrategy != "" {
|
||||
return cheCluster.Spec.K8s.IngressStrategy
|
||||
}
|
||||
|
||||
// Explicitly switch to `single-host` mode
|
||||
if cheCluster.Spec.DevWorkspace.Enable {
|
||||
return "single-host"
|
||||
}
|
||||
|
||||
return "multi-host"
|
||||
}
|
||||
|
||||
func IsTestMode() (isTesting bool) {
|
||||
testMode := os.Getenv("MOCK_API")
|
||||
if len(testMode) == 0 {
|
||||
|
|
@ -224,103 +203,6 @@ func IsTestMode() (isTesting bool) {
|
|||
return true
|
||||
}
|
||||
|
||||
func GetOpenShiftAPIUrls() (string, string, error) {
|
||||
// for debug purpose
|
||||
apiUrl := os.Getenv("CLUSTER_API_URL")
|
||||
apiInternalUrl := os.Getenv("CLUSTER_API_INTERNAL_URL")
|
||||
if apiUrl != "" || apiInternalUrl != "" {
|
||||
return apiUrl, apiInternalUrl, nil
|
||||
}
|
||||
|
||||
if IsOpenShift4 {
|
||||
return getAPIUrlsForOpenShiftV4()
|
||||
}
|
||||
|
||||
return getAPIUrlsForOpenShiftV3()
|
||||
}
|
||||
|
||||
// getAPIUrlsForOpenShiftV3 is a hacky way to get OpenShift API public DNS/IP
|
||||
// to be used in OpenShift oAuth provider as baseURL
|
||||
func getAPIUrlsForOpenShiftV3() (apiUrl string, apiInternalUrl string, err error) {
|
||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
client := &http.Client{}
|
||||
kubeApi := os.Getenv("KUBERNETES_PORT_443_TCP_ADDR")
|
||||
url := "https://" + kubeApi + "/.well-known/oauth-authorization-server"
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logrus.Errorf("An error occurred when getting API public hostname: %s", err)
|
||||
return "", "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logrus.Errorf("An error occurred when getting API public hostname: %s", err)
|
||||
return "", "", err
|
||||
}
|
||||
var jsonData map[string]interface{}
|
||||
err = json.Unmarshal(body, &jsonData)
|
||||
if err != nil {
|
||||
logrus.Errorf("An error occurred when unmarshalling: %s", err)
|
||||
return "", "", err
|
||||
}
|
||||
apiUrl = jsonData["issuer"].(string)
|
||||
return apiUrl, "", nil
|
||||
}
|
||||
|
||||
// getClusterPublicHostnameForOpenshiftV3 is a way to get OpenShift API public DNS/IP
|
||||
// to be used in OpenShift oAuth provider as baseURL
|
||||
func getAPIUrlsForOpenShiftV4() (apiUrl string, apiInternalUrl string, err error) {
|
||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
client := &http.Client{}
|
||||
kubeApi := os.Getenv("KUBERNETES_PORT_443_TCP_ADDR")
|
||||
url := "https://" + kubeApi + "/apis/config.openshift.io/v1/infrastructures/cluster"
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
file, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to locate token file: %s", err)
|
||||
return "", "", err
|
||||
}
|
||||
token := string(file)
|
||||
|
||||
req.Header = http.Header{
|
||||
"Authorization": []string{"Bearer " + token},
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logrus.Errorf("An error occurred when getting API public hostname: %s", err)
|
||||
return "", "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode/100 != 2 {
|
||||
message := url + " - " + resp.Status
|
||||
logrus.Errorf("An error occurred when getting API public hostname: %s", message)
|
||||
return "", "", errors.New(message)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logrus.Errorf("An error occurred when getting API public hostname: %s", err)
|
||||
return "", "", err
|
||||
}
|
||||
var jsonData map[string]interface{}
|
||||
err = json.Unmarshal(body, &jsonData)
|
||||
if err != nil {
|
||||
logrus.Errorf("An error occurred when unmarshalling while getting API public hostname: %s", err)
|
||||
return "", "", err
|
||||
}
|
||||
switch status := jsonData["status"].(type) {
|
||||
case map[string]interface{}:
|
||||
apiUrl = status["apiServerURL"].(string)
|
||||
apiInternalUrl = status["apiServerInternalURI"].(string)
|
||||
default:
|
||||
logrus.Errorf("An error occurred when unmarshalling while getting API public hostname: %s", body)
|
||||
return "", "", errors.New(string(body))
|
||||
}
|
||||
|
||||
return apiUrl, apiInternalUrl, nil
|
||||
}
|
||||
|
||||
func GetRouterCanonicalHostname(client client.Client, namespace string) (string, error) {
|
||||
testRouteYaml, err := GetTestRouteYaml(client, namespace)
|
||||
if err != nil {
|
||||
|
|
@ -479,22 +361,6 @@ func NewBoolPointer(value bool) *bool {
|
|||
return &variable
|
||||
}
|
||||
|
||||
// GetWorkspaceNamespaceDefault - returns workspace namespace default strategy, which points on the namespaces used for workspaces execution.
|
||||
func GetWorkspaceNamespaceDefault(cr *orgv1.CheCluster) string {
|
||||
if cr.Spec.Server.CustomCheProperties != nil {
|
||||
k8sNamespaceDefault := cr.Spec.Server.CustomCheProperties["CHE_INFRA_KUBERNETES_NAMESPACE_DEFAULT"]
|
||||
if k8sNamespaceDefault != "" {
|
||||
return k8sNamespaceDefault
|
||||
}
|
||||
}
|
||||
|
||||
workspaceNamespaceDefault := cr.Namespace
|
||||
if IsOpenShift && cr.IsOpenShiftOAuthEnabled() {
|
||||
workspaceNamespaceDefault = "<username>-" + cr.Spec.Server.CheFlavor
|
||||
}
|
||||
return GetValue(cr.Spec.Server.WorkspaceNamespaceDefault, workspaceNamespaceDefault)
|
||||
}
|
||||
|
||||
func GetResourceQuantity(value string, defaultValue string) resource.Quantity {
|
||||
if value != "" {
|
||||
return resource.MustParse(value)
|
||||
|
|
@ -565,11 +431,5 @@ func ClearMetadata(objectMeta *metav1.ObjectMeta) {
|
|||
|
||||
// GetCheURL returns Che url.
|
||||
func GetCheURL(cheCluster *orgv1.CheCluster) string {
|
||||
var cheUrl string
|
||||
if cheCluster.Spec.Server.TlsSupport {
|
||||
cheUrl = "https://" + cheCluster.Spec.Server.CheHost
|
||||
} else {
|
||||
cheUrl = "http://" + cheCluster.Spec.Server.CheHost
|
||||
}
|
||||
return cheUrl
|
||||
return "https://" + cheCluster.Spec.Server.CheHost
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2019-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
|
||||
#
|
||||
|
||||
connectToKeycloak() {
|
||||
{{ .Script }} config credentials --server http://0.0.0.0:8080/auth --realm master --user {{ .KeycloakAdminUserName }} --password {{ .KeycloakAdminPassword }}
|
||||
}
|
||||
|
||||
createIdentityProvider() {
|
||||
{{ .Script }} get identity-provider/instances/{{ .ProviderId }} -r {{ .KeycloakRealm }}
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "{{ .ProviderId }} identity provider exists."
|
||||
else
|
||||
echo "Create new {{ .ProviderId }} identity provider."
|
||||
if [ -z "${GITHUB_CLIENT_ID}" ] || [ -z "${GITHUB_SECRET}" ]; then
|
||||
echo "Either 'GITHUB_CLIENT_ID' or 'GITHUB_SECRET' aren't set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
{{ .Script }} create identity-provider/instances \
|
||||
-r {{ .KeycloakRealm }} \
|
||||
-s alias={{ .ProviderId }} \
|
||||
-s providerId={{ .ProviderId }} \
|
||||
-s enabled=true \
|
||||
-s storeToken=true \
|
||||
-s config.useJwksUrl=true \
|
||||
-s config.clientId=${GITHUB_CLIENT_ID} \
|
||||
-s config.clientSecret=${GITHUB_SECRET} \
|
||||
-s config.defaultScope=repo,user,write:public_key
|
||||
fi
|
||||
}
|
||||
|
||||
connectToKeycloak
|
||||
createIdentityProvider
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2019-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
|
||||
#
|
||||
|
||||
connectToKeycloak() {
|
||||
{{ .Script }} config credentials --server http://0.0.0.0:8080/auth --realm master --user {{ .KeycloakAdminUserName }} --password {{ .KeycloakAdminPassword }}
|
||||
}
|
||||
|
||||
deleteIdentityProvider() {
|
||||
{{ .Script }} get identity-provider/instances/{{ .ProviderId }} -r {{ .KeycloakRealm }}
|
||||
if [ ! $? -eq 0 ]; then
|
||||
echo "{{ .ProviderId }} identity provider does not exists."
|
||||
else
|
||||
echo "Delete {{ .ProviderId }} identity provider."
|
||||
{{ .Script }} delete identity-provider/instances/{{ .ProviderId }} -r {{ .KeycloakRealm }}
|
||||
fi
|
||||
}
|
||||
|
||||
connectToKeycloak
|
||||
deleteIdentityProvider
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2019-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
|
||||
#
|
||||
|
||||
connectToKeycloak() {
|
||||
{{ .Script }} config credentials --server http://0.0.0.0:8080/auth --realm master --user {{ .KeycloakAdminUserName }} --password {{ .KeycloakAdminPassword }}
|
||||
}
|
||||
|
||||
provisionKeycloak() {
|
||||
{{ .Script }} update realms/master -s sslRequired=none
|
||||
{{ .Script }} config truststore --trustpass ${SSO_TRUSTSTORE_PASSWORD} ${SSO_TRUSTSTORE_DIR}/${SSO_TRUSTSTORE}
|
||||
|
||||
{{ .Script }} get realms/{{ .KeycloakRealm }}
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "{{ .KeycloakRealm }} realm exists."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Provision {{ .KeycloakRealm }} realm."
|
||||
{{ .Script }} create realms \
|
||||
-s realm='{{ .KeycloakRealm }}' \
|
||||
-s displayName='{{ .RealmDisplayName }}' \
|
||||
-s enabled=true \
|
||||
-s sslRequired=none \
|
||||
-s registrationAllowed=false \
|
||||
-s resetPasswordAllowed=true \
|
||||
-s loginTheme={{ .KeycloakTheme }} \
|
||||
-s accountTheme={{ .KeycloakTheme }} \
|
||||
-s adminTheme={{ .KeycloakTheme }} \
|
||||
-s emailTheme={{ .KeycloakTheme }}
|
||||
|
||||
DEFAULT_WEBORIGINS='"http://{{ .CheHost }}", "https://{{ .CheHost }}"'
|
||||
# ADDITIONAL_WEBORIGINS is an env var in format '"url1", "url2"'
|
||||
# which if specified, is provisioned to keycloak additionally to Che's URLs ones
|
||||
[ ! -z "$ADDITIONAL_WEBORIGINS" ] && ADDITIONAL_WEBORIGINS=", $ADDITIONAL_WEBORIGINS"
|
||||
WEBORIGINS="[$DEFAULT_WEBORIGINS $ADDITIONAL_WEBORIGINS]"
|
||||
|
||||
DEFAULT_REDIRECT_URIS='"http://{{ .CheHost }}/dashboard/*", "https://{{ .CheHost }}/dashboard/*", "http://{{ .CheHost }}/factory*", "https://{{ .CheHost }}/factory*", "http://{{ .CheHost }}/f*", "https://{{ .CheHost }}/f*", "http://{{ .CheHost }}/_app/*", "https://{{ .CheHost }}/_app/*", "http://{{ .CheHost }}/swagger/*", "https://{{ .CheHost }}/swagger/*"'
|
||||
# ADDITIONAL_REDIRECT_URIS is an env var in format '"url1", "url2"'
|
||||
# which if specified, is provisioned to keycloak additionally to Che's URLs ones
|
||||
[ ! -z "$ADDITIONAL_REDIRECT_URIS" ] && ADDITIONAL_REDIRECT_URIS=", $ADDITIONAL_REDIRECT_URIS"
|
||||
REDIRECT_URIS="[$DEFAULT_REDIRECT_URIS $ADDITIONAL_REDIRECT_URIS]"
|
||||
|
||||
{{ .Script }} create clients \
|
||||
-r '{{ .KeycloakRealm }}' \
|
||||
-s clientId={{ .KeycloakClientId }} \
|
||||
-s id={{ .KeycloakClientId }} \
|
||||
-s webOrigins="$WEBORIGINS" \
|
||||
-s redirectUris="$REDIRECT_URIS" \
|
||||
-s directAccessGrantsEnabled=true \
|
||||
-s publicClient=true
|
||||
|
||||
{{ .Script }} create users \
|
||||
-r '{{ .KeycloakRealm }}' \
|
||||
-s username=admin \
|
||||
-s email=\"admin@admin.com\" \
|
||||
-s enabled=true \
|
||||
-s requiredActions='[{{ .RequiredActions }}]'
|
||||
|
||||
{{ .Script }} set-password \
|
||||
-r '{{ .KeycloakRealm }}' \
|
||||
--username admin \
|
||||
--new-password admin
|
||||
|
||||
user_id=$( {{ .Script }} get users -r '{{ .KeycloakRealm }}' -q username=admin --fields 'id' --format csv --noquotes )
|
||||
{{ .Script }} update users/${user_id} -r '{{ .KeycloakRealm }}' -s requiredActions='[{{ .RequiredActions }}]'
|
||||
|
||||
{{ .Script }} add-roles \
|
||||
-r '{{ .KeycloakRealm }}' \
|
||||
--uusername admin \
|
||||
--cclientid broker \
|
||||
--rolename read-token
|
||||
|
||||
CLIENT_ID=$({{ .Script }} get clients -r '{{ .KeycloakRealm }}' -q clientId=broker | sed -n 's/.*"id" *: *"\([^"]\+\).*/\1/p')
|
||||
{{ .Script }} update clients/${CLIENT_ID} \
|
||||
-r '{{ .KeycloakRealm }}' \
|
||||
-s "defaultRoles+=read-token"
|
||||
}
|
||||
|
||||
connectToKeycloak
|
||||
provisionKeycloak
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2019-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
|
||||
#
|
||||
|
||||
connectToKeycloak() {
|
||||
{{ .Script }} config credentials --server http://0.0.0.0:8080/auth --realm master --user {{ .KeycloakAdminUserName }} --password {{ .KeycloakAdminPassword }}
|
||||
}
|
||||
|
||||
updateKeycloak() {
|
||||
DEFAULT_WEBORIGINS='"http://{{ .CheHost }}", "https://{{ .CheHost }}"'
|
||||
# ADDITIONAL_WEBORIGINS is an env var in format '"url1", "url2"'
|
||||
# which if specified, is provisioned to keycloak additionally to Che's URLs ones
|
||||
[ ! -z "$ADDITIONAL_WEBORIGINS" ] && ADDITIONAL_WEBORIGINS=", $ADDITIONAL_WEBORIGINS"
|
||||
WEBORIGINS="[$DEFAULT_WEBORIGINS $ADDITIONAL_WEBORIGINS]"
|
||||
|
||||
DEFAULT_REDIRECT_URIS='"http://{{ .CheHost }}/dashboard/*", "https://{{ .CheHost }}/dashboard/*", "http://{{ .CheHost }}/factory*", "https://{{ .CheHost }}/factory*", "http://{{ .CheHost }}/f*", "https://{{ .CheHost }}/f*", "http://{{ .CheHost }}/_app/*", "https://{{ .CheHost }}/_app/*", "http://{{ .CheHost }}/swagger/*", "https://{{ .CheHost }}/swagger/*"'
|
||||
# ADDITIONAL_REDIRECT_URIS is an env var in format '"url1", "url2"'
|
||||
# which if specified, is provisioned to keycloak additionally to Che's URLs ones
|
||||
[ ! -z "$ADDITIONAL_REDIRECT_URIS" ] && ADDITIONAL_REDIRECT_URIS=", $ADDITIONAL_REDIRECT_URIS"
|
||||
REDIRECT_URIS="[$DEFAULT_REDIRECT_URIS $ADDITIONAL_REDIRECT_URIS]"
|
||||
|
||||
{{ .Script }} update clients/{{ .KeycloakClientId }} \
|
||||
-r '{{ .KeycloakRealm }}' \
|
||||
-s webOrigins="$WEBORIGINS" \
|
||||
-s redirectUris="$REDIRECT_URIS"
|
||||
}
|
||||
|
||||
checkKeycloak() {
|
||||
REDIRECT_URIS=$({{ .Script }} get clients/{{ .KeycloakClientId }} -r '{{ .KeycloakRealm }}' | jq '.redirectUris')
|
||||
FIND="http://{{ .CheHost }}/factory*"
|
||||
for URI in "${REDIRECT_URIS[@]}"; do
|
||||
[[ $FIND == "$URI" ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
connectToKeycloak
|
||||
checkKeycloak
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
updateKeycloak
|
||||
fi
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2019-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
|
||||
#
|
||||
|
||||
connect_to_keycloak() {
|
||||
{{ .Script }} config credentials --server http://0.0.0.0:8080/auth --realm master --user {{ .KeycloakAdminUserName }} --password {{ .KeycloakAdminPassword }}
|
||||
{{ .Script }} config truststore --trustpass ${SSO_TRUSTSTORE_PASSWORD} ${SSO_TRUSTSTORE_DIR}/${SSO_TRUSTSTORE}
|
||||
}
|
||||
|
||||
create_identity_provider() {
|
||||
{{ .Script }} get identity-provider/instances/{{ .ProviderId }} -r {{ .KeycloakRealm }}
|
||||
if [ $? -eq 0 ]
|
||||
then echo "Provider exists"
|
||||
else {{ .Script }} create identity-provider/instances -r {{ .KeycloakRealm }} -s alias={{ .ProviderId }} -s providerId={{ .ProviderId }} -s enabled=true -s storeToken=true -s addReadTokenRoleOnCreate=true -s config.useJwksUrl=true -s config.clientId={{ .OAuthClientName}} -s config.clientSecret={{ .OauthSecret}} -s config.baseUrl={{ .OpenShiftApiUrl }} -s config.defaultScope=user:full
|
||||
fi
|
||||
}
|
||||
|
||||
default_to_openshift_login() {
|
||||
EXECUTION_ID=$({{ .Script }} get authentication/flows/browser/executions -r {{ .KeycloakRealm }} -c | sed -e 's/.*\({[^}]\+"identity-provider-redirector"[^}]\+}\).*/\1/' -e 's/.*"id":"\([^"]\+\)".*/\1/')
|
||||
ALIAS=$({{ .Script }} get authentication/flows/browser/executions -r {{ .KeycloakRealm }} -c | sed -e 's/.*\({[^}]\+"identity-provider-redirector"[^}]\+}\).*/\1/' | grep '"alias":"' | sed -e 's/.*"alias":"\([^"]\+\)".*/\1/')
|
||||
if [ "${EXECUTION_ID}" == "" ]
|
||||
then
|
||||
echo "Could not find the identity provider redirector"
|
||||
return 1
|
||||
fi
|
||||
if [ -z ${ALIAS} ];
|
||||
then
|
||||
echo '{"config":{"defaultProvider":"{{ .ProviderId }}"},"alias":"{{ .ProviderId }}"}' | {{ .Script }} create -r {{ .KeycloakRealm }} authentication/executions/${EXECUTION_ID}/config -f -
|
||||
fi
|
||||
}
|
||||
|
||||
enable_openshift_token-exchange() {
|
||||
IDENTITY_PROVIDER_ID=$({{ .Script }} get -r {{ .KeycloakRealm }} identity-provider/instances/{{ .ProviderId }} | grep -e '"internalId" *: *"' | sed -e 's/.*"internalId" *: *"\([^"]\+\)".*/\1/')
|
||||
if [ "${IDENTITY_PROVIDER_ID}" == "" ]
|
||||
then
|
||||
echo "identity provider not found"
|
||||
return 1
|
||||
fi
|
||||
echo '{"enabled": true}' | {{ .Script }} update -r {{ .KeycloakRealm }} identity-provider/instances/{{ .ProviderId }}/management/permissions -f -
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "failed to enable permissions on identity provider"
|
||||
return 1
|
||||
fi
|
||||
TOKEN_EXCHANGE_PERMISSIONS=$({{ .Script }} get -r {{ .KeycloakRealm }} identity-provider/instances/{{ .ProviderId }}/management/permissions)
|
||||
if [ "${TOKEN_EXCHANGE_PERMISSIONS}" == "" ]
|
||||
then
|
||||
echo "token exchange permissions not found"
|
||||
return 1
|
||||
fi
|
||||
TOKEN_EXCHANGE_RESOURCE=$(echo ${TOKEN_EXCHANGE_PERMISSIONS} | grep -e '"resource" *: *"' | sed -e 's/.*"resource" *: *"\([^"]\+\)".*/\1/')
|
||||
TOKEN_EXCHANGE_PERMISSION_ID=$(echo ${TOKEN_EXCHANGE_PERMISSIONS} | sed -e 's/.*"scopePermissions" *: *{ *"token-exchange" *: *"\([^"]\+\)".*/\1/')
|
||||
if [ "${TOKEN_EXCHANGE_RESOURCE}" == "" ] || [ "${TOKEN_EXCHANGE_PERMISSION_ID}" == "" ]
|
||||
then
|
||||
echo "token exchange permissions do not contain expected values"
|
||||
return 1
|
||||
fi
|
||||
REALM_MGMT_CLIENT_ID=$({{ .Script }} get -r {{ .KeycloakRealm }} clients -q clientId=realm-management | grep -e '"id" *: *"' | sed -e 's/.*"id" *: *"\([^"]\+\)".*/\1/')
|
||||
if [ "${REALM_MGMT_CLIENT_ID}" == "" ]
|
||||
then
|
||||
echo "Realm management client ID not found"
|
||||
return 1
|
||||
fi
|
||||
EXISTING_POLICY=$({{ .Script }} get -r {{ .KeycloakRealm }} clients/${REALM_MGMT_CLIENT_ID}/authz/resource-server/policy/client -q 'name={{ .ProviderId }}' | grep -e '"id" *: *"' | sed -e 's/.*"id" *: *"\([^"]\+\)".*/\1/')
|
||||
if [ "${EXISTING_POLICY}" == "" ]
|
||||
then
|
||||
echo '{"type":"client","logic":"POSITIVE","decisionStrategy":"UNANIMOUS","name":"{{ .ProviderId }}","clients":["{{ .KeycloakClientId }}"]}' | {{ .Script }} create -r {{ .KeycloakRealm }} clients/${REALM_MGMT_CLIENT_ID}/authz/resource-server/policy/client -f -
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "Failed to create policy"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
TOKEN_EXCHANGE_POLICY=$({{ .Script }} get -r {{ .KeycloakRealm }} clients/${REALM_MGMT_CLIENT_ID}/authz/resource-server/policy/client -q 'name={{ .ProviderId }}' | grep -e '"id" *: *"' | sed -e 's/.*"id" *: *"\([^"]\+\)".*/\1/')
|
||||
if [ "${TOKEN_EXCHANGE_POLICY}" == "" ]
|
||||
then
|
||||
echo "Token exchange policy not found"
|
||||
return 1
|
||||
fi
|
||||
TOKEN_EXCHANGE_PERMISSION=$({{ .Script }} get -r {{ .KeycloakRealm }} clients/${REALM_MGMT_CLIENT_ID}/authz/resource-server/permission/scope/${TOKEN_EXCHANGE_PERMISSION_ID})
|
||||
if [ "${TOKEN_EXCHANGE_PERMISSION}" == "" ]
|
||||
then
|
||||
echo "Token exchange permission not found"
|
||||
return 1
|
||||
fi
|
||||
TOKEN_EXCHANGE_SCOPES=$({{ .Script }} get -r {{ .KeycloakRealm }} clients/${REALM_MGMT_CLIENT_ID}/authz/resource-server/resource/${TOKEN_EXCHANGE_RESOURCE}/scopes)
|
||||
if [ "${TOKEN_EXCHANGE_SCOPES}" == "" ]
|
||||
then
|
||||
echo "Token exchange scopes not found"
|
||||
return 1
|
||||
fi
|
||||
TOKEN_EXCHANGE_SCOPE=$(echo ${TOKEN_EXCHANGE_SCOPES} | sed -e 's/.*"id" *: *"\([^"]\+\)" *, *"name" *: *"token-exchange".*/\1/')
|
||||
if [ "${TOKEN_EXCHANGE_SCOPE}" == "" ]
|
||||
then
|
||||
echo "Token exchange scope not found"
|
||||
return 1
|
||||
fi
|
||||
PERMISSION_RESOURCES=$(echo ${TOKEN_EXCHANGE_PERMISSION} | grep -e 'resources *:')
|
||||
if [ "${PERMISSION_RESOURCES}" == "" ]
|
||||
then
|
||||
echo ${TOKEN_EXCHANGE_PERMISSION} | sed -e "s/ *{\(.*}\) */{\"resources\":[\"${TOKEN_EXCHANGE_RESOURCE}\"],\"scopes\":[\"${TOKEN_EXCHANGE_SCOPE}\"],\"policies\":[\"${TOKEN_EXCHANGE_POLICY}\"],\1/" | {{ .Script }} update -r {{ .KeycloakRealm }} clients/${REALM_MGMT_CLIENT_ID}/authz/resource-server/permission/scope/${TOKEN_EXCHANGE_PERMISSION_ID} -f -
|
||||
fi
|
||||
}
|
||||
|
||||
set -x
|
||||
connect_to_keycloak && create_identity_provider && default_to_openshift_login && enable_openshift_token-exchange
|
||||
Loading…
Reference in New Issue