Code clean up 4 (#761)

* Refactoring plugin and devfile registries

Signed-off-by: Anatolii Bazko <abazko@redhat.com>
pull/770/head
Anatolii Bazko 2021-04-13 11:18:15 +03:00 committed by GitHub
parent 209ec4c02b
commit e6491cc323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 840 additions and 624 deletions

View File

@ -22,10 +22,10 @@ import (
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
"github.com/eclipse-che/che-operator/pkg/deploy"
devworkspace "github.com/eclipse-che/che-operator/pkg/deploy/dev-workspace"
devfile_registry "github.com/eclipse-che/che-operator/pkg/deploy/devfile-registry"
"github.com/eclipse-che/che-operator/pkg/deploy/devfileregistry"
"github.com/eclipse-che/che-operator/pkg/deploy/gateway"
identity_provider "github.com/eclipse-che/che-operator/pkg/deploy/identity-provider"
plugin_registry "github.com/eclipse-che/che-operator/pkg/deploy/plugin-registry"
"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/server"
"github.com/eclipse-che/che-operator/pkg/util"
@ -343,9 +343,8 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
deployContext := &deploy.DeployContext{
ClusterAPI: clusterAPI,
CheCluster: instance,
InternalService: deploy.InternalService{},
ClusterAPI: clusterAPI,
CheCluster: instance,
}
// Reconcile finalizers before CR is deleted
@ -566,38 +565,6 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
}
// If the devfile-registry ConfigMap exists, and we are not in airgapped mode, delete the ConfigMap
devfileRegistryConfigMap := &corev1.ConfigMap{}
err = r.client.Get(context.TODO(), types.NamespacedName{Namespace: instance.Namespace, Name: deploy.DevfileRegistryName}, devfileRegistryConfigMap)
if err != nil && !errors.IsNotFound(err) {
logrus.Errorf("Error getting devfile-registry ConfigMap: %v", err)
return reconcile.Result{}, err
}
if err == nil && instance.Spec.Server.ExternalDevfileRegistry {
logrus.Info("Found devfile-registry ConfigMap and while using an external devfile registry. Deleting.")
if err = r.client.Delete(context.TODO(), devfileRegistryConfigMap); err != nil {
logrus.Errorf("Error deleting devfile-registry ConfigMap: %v", err)
return reconcile.Result{}, err
}
return reconcile.Result{Requeue: true}, nil
}
// If the plugin-registry ConfigMap exists, and we are not in airgapped mode, delete the ConfigMap
pluginRegistryConfigMap := &corev1.ConfigMap{}
err = r.client.Get(context.TODO(), types.NamespacedName{Namespace: instance.Namespace, Name: deploy.PluginRegistryName}, pluginRegistryConfigMap)
if err != nil && !errors.IsNotFound(err) {
logrus.Errorf("Error getting plugin-registry ConfigMap: %v", err)
return reconcile.Result{}, err
}
if err == nil && !instance.IsAirGapMode() {
logrus.Info("Found plugin-registry ConfigMap and not in airgap mode. Deleting.")
if err = r.client.Delete(context.TODO(), pluginRegistryConfigMap); err != nil {
logrus.Errorf("Error deleting plugin-registry ConfigMap: %v", err)
return reconcile.Result{}, err
}
return reconcile.Result{Requeue: true}, nil
}
if err := r.SetStatusDetails(instance, request, "", "", ""); err != nil {
return reconcile.Result{}, err
}
@ -719,13 +686,15 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
postgres := postgres.NewPostgres(deployContext)
done, err = postgres.Sync()
if !done {
if err != nil {
logrus.Error(err)
if !deployContext.CheCluster.Spec.Database.ExternalDb {
postgres := postgres.NewPostgres(deployContext)
done, err = postgres.SyncAll()
if !done {
if err != nil {
logrus.Error(err)
}
return reconcile.Result{}, err
}
return reconcile.Result{}, err
}
tlsSupport := instance.Spec.Server.TlsSupport
@ -744,8 +713,6 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
return reconcile.Result{}, err
}
deployContext.InternalService.CheHost = fmt.Sprintf("http://%s.%s.svc:8080", deploy.CheServiceName, deployContext.CheCluster.Namespace)
exposedServiceName := getServerExposingServiceName(instance)
cheHost := ""
if !isOpenShift {
@ -831,23 +798,44 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
provisioned, err = devfile_registry.SyncDevfileRegistryToCluster(deployContext)
if !tests {
if !provisioned {
if !instance.Spec.Server.ExternalPluginRegistry {
pluginRegistry := pluginregistry.NewPluginRegistry(deployContext)
done, err := pluginRegistry.SyncAll()
if !done {
if err != nil {
logrus.Errorf("Error provisioning '%s' to cluster: %v", deploy.DevfileRegistryName, err)
logrus.Error(err)
}
return reconcile.Result{}, err
}
} else {
if instance.Spec.Server.PluginRegistryUrl != instance.Status.PluginRegistryURL {
instance.Status.PluginRegistryURL = instance.Spec.Server.PluginRegistryUrl
if err := r.UpdateCheCRStatus(instance, "status: Plugin Registry URL", instance.Spec.Server.PluginRegistryUrl); err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{RequeueAfter: time.Second * 1}, err
}
}
provisioned, err = plugin_registry.SyncPluginRegistryToCluster(deployContext)
if !tests {
if !provisioned {
if !instance.Spec.Server.ExternalDevfileRegistry {
devfileRegistry := devfileregistry.NewDevfileRegistry(deployContext)
done, err := devfileRegistry.SyncAll()
if !done {
if err != nil {
logrus.Errorf("Error provisioning '%s' to cluster: %v", deploy.PluginRegistryName, err)
logrus.Error(err)
}
return reconcile.Result{}, err
}
} else {
done, err := deploy.DeleteNamespacedObject(deployContext, deploy.DevfileRegistryName, &corev1.ConfigMap{})
if !done {
return reconcile.Result{}, err
}
if instance.Spec.Server.DevfileRegistryUrl != instance.Status.DevfileRegistryURL {
instance.Status.DevfileRegistryURL = instance.Spec.Server.DevfileRegistryUrl
if err := r.UpdateCheCRStatus(instance, "status: Devfile Registry URL", instance.Spec.Server.DevfileRegistryUrl); err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{RequeueAfter: time.Second * 1}, err
}
}

View File

@ -26,18 +26,10 @@ type ProvisioningStatus struct {
}
type DeployContext struct {
CheCluster *orgv1.CheCluster
ClusterAPI ClusterAPI
Proxy *Proxy
InternalService InternalService
DefaultCheHost string
}
type InternalService struct {
KeycloakHost string
DevfileRegistryHost string
PluginRegistryHost string
CheHost string
CheCluster *orgv1.CheCluster
ClusterAPI ClusterAPI
Proxy *Proxy
DefaultCheHost string
}
type ClusterAPI struct {

View File

@ -1,114 +0,0 @@
//
// Copyright (c) 2012-2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devfile_registry
import (
"encoding/json"
"fmt"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/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/sirupsen/logrus"
)
type DevFileRegistryConfigMap struct {
CheDevfileImagesRegistryURL string `json:"CHE_DEVFILE_IMAGES_REGISTRY_URL"`
CheDevfileImagesRegistryOrganization string `json:"CHE_DEVFILE_IMAGES_REGISTRY_ORGANIZATION"`
CheDevfileRegistryURL string `json:"CHE_DEVFILE_REGISTRY_URL"`
}
/**
* Create devfile registry resources unless an external registry is used.
*/
func SyncDevfileRegistryToCluster(deployContext *deploy.DeployContext) (bool, error) {
devfileRegistryURL := deployContext.CheCluster.Spec.Server.DevfileRegistryUrl
if !deployContext.CheCluster.Spec.Server.ExternalDevfileRegistry {
endpoint, done, err := expose.Expose(
deployContext,
deploy.DevfileRegistryName,
deployContext.CheCluster.Spec.Server.DevfileRegistryRoute,
deployContext.CheCluster.Spec.Server.DevfileRegistryIngress)
if !done {
return false, err
}
if devfileRegistryURL == "" {
if deployContext.CheCluster.Spec.Server.TlsSupport {
devfileRegistryURL = "https://" + endpoint
} else {
devfileRegistryURL = "http://" + endpoint
}
}
configMapData := getDevfileRegistryConfigMapData(deployContext.CheCluster, devfileRegistryURL)
done, err = deploy.SyncConfigMapDataToCluster(deployContext, deploy.DevfileRegistryName, configMapData, deploy.DevfileRegistryName)
if !done {
return false, err
}
// Create a new registry service
done, err = deploy.SyncServiceToCluster(deployContext, deploy.DevfileRegistryName, []string{"http"}, []int32{8080}, deploy.DevfileRegistryName)
if !util.IsTestMode() {
if !done {
if err != nil {
logrus.Error(err)
}
return false, err
}
}
deployContext.InternalService.DevfileRegistryHost = fmt.Sprintf("http://%s.%s.svc:8080", deploy.DevfileRegistryName, deployContext.CheCluster.Namespace)
// Deploy devfile registry
provisioned, err := SyncDevfileRegistryDeploymentToCluster(deployContext)
if !util.IsTestMode() {
if !provisioned {
logrus.Info("Waiting on deployment '" + deploy.DevfileRegistryName + "' to be ready")
if err != nil {
logrus.Error(err)
}
return provisioned, err
}
}
}
if devfileRegistryURL != deployContext.CheCluster.Status.DevfileRegistryURL {
deployContext.CheCluster.Status.DevfileRegistryURL = devfileRegistryURL
if err := deploy.UpdateCheCRStatus(deployContext, "status: Devfile Registry URL", devfileRegistryURL); err != nil {
return false, err
}
}
return true, nil
}
func getDevfileRegistryConfigMapData(cr *orgv1.CheCluster, endpoint string) map[string]string {
devfileRegistryEnv := make(map[string]string)
data := &DevFileRegistryConfigMap{
CheDevfileImagesRegistryURL: cr.Spec.Server.AirGapContainerRegistryHostname,
CheDevfileImagesRegistryOrganization: cr.Spec.Server.AirGapContainerRegistryOrganization,
CheDevfileRegistryURL: endpoint,
}
out, err := json.Marshal(data)
if err != nil {
fmt.Println(err)
}
err = json.Unmarshal(out, &devfileRegistryEnv)
if err != nil {
fmt.Println(err)
}
return devfileRegistryEnv
}

View File

@ -0,0 +1,104 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devfileregistry
import (
"github.com/eclipse-che/che-operator/pkg/deploy"
"github.com/eclipse-che/che-operator/pkg/deploy/expose"
)
type DevfileRegistry struct {
deployContext *deploy.DeployContext
}
func NewDevfileRegistry(deployContext *deploy.DeployContext) *DevfileRegistry {
return &DevfileRegistry{
deployContext: deployContext,
}
}
func (p *DevfileRegistry) SyncAll() (bool, error) {
done, err := p.SyncService()
if !done {
return false, err
}
endpoint, done, err := p.ExposeEndpoint()
if !done {
return false, err
}
done, err = p.UpdateStatus(endpoint)
if !done {
return false, err
}
done, err = p.SyncConfigMap()
if !done {
return false, err
}
done, err = p.SyncDeployment()
if !done {
return false, err
}
return true, nil
}
func (p *DevfileRegistry) SyncService() (bool, error) {
return deploy.SyncServiceToCluster(
p.deployContext,
deploy.DevfileRegistryName,
[]string{"http"},
[]int32{8080},
deploy.DevfileRegistryName)
}
func (p *DevfileRegistry) SyncConfigMap() (bool, error) {
data, err := p.GetConfigMapData()
if err != nil {
return false, err
}
return deploy.SyncConfigMapDataToCluster(p.deployContext, deploy.DevfileRegistryName, data, deploy.DevfileRegistryName)
}
func (p *DevfileRegistry) ExposeEndpoint() (string, bool, error) {
return expose.Expose(
p.deployContext,
deploy.DevfileRegistryName,
p.deployContext.CheCluster.Spec.Server.DevfileRegistryRoute,
p.deployContext.CheCluster.Spec.Server.DevfileRegistryIngress)
}
func (p *DevfileRegistry) UpdateStatus(endpoint string) (bool, error) {
var devfileRegistryURL string
if p.deployContext.CheCluster.Spec.Server.TlsSupport {
devfileRegistryURL = "https://" + endpoint
} else {
devfileRegistryURL = "http://" + endpoint
}
if devfileRegistryURL != p.deployContext.CheCluster.Status.DevfileRegistryURL {
p.deployContext.CheCluster.Status.DevfileRegistryURL = devfileRegistryURL
if err := deploy.UpdateCheCRStatus(p.deployContext, "status: Devfile Registry URL", devfileRegistryURL); err != nil {
return false, err
}
}
return true, nil
}
func (p *DevfileRegistry) SyncDeployment() (bool, error) {
spec := p.GetDevfileRegistryDeploymentSpec()
return deploy.SyncDeploymentSpecToCluster(p.deployContext, spec, deploy.DefaultDeploymentDiffOpts)
}

View File

@ -0,0 +1,43 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devfileregistry
import (
"encoding/json"
)
type DevFileRegistryConfigMap struct {
CheDevfileImagesRegistryURL string `json:"CHE_DEVFILE_IMAGES_REGISTRY_URL"`
CheDevfileImagesRegistryOrganization string `json:"CHE_DEVFILE_IMAGES_REGISTRY_ORGANIZATION"`
CheDevfileRegistryURL string `json:"CHE_DEVFILE_REGISTRY_URL"`
}
func (p *DevfileRegistry) GetConfigMapData() (map[string]string, error) {
devfileRegistryEnv := make(map[string]string)
data := &DevFileRegistryConfigMap{
CheDevfileImagesRegistryURL: p.deployContext.CheCluster.Spec.Server.AirGapContainerRegistryHostname,
CheDevfileImagesRegistryOrganization: p.deployContext.CheCluster.Spec.Server.AirGapContainerRegistryOrganization,
CheDevfileRegistryURL: p.deployContext.CheCluster.Status.DevfileRegistryURL,
}
out, err := json.Marshal(data)
if err != nil {
return nil, err
}
err = json.Unmarshal(out, &devfileRegistryEnv)
if err != nil {
return nil, err
}
return devfileRegistryEnv, nil
}

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2020-2020 Red Hat, Inc.
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
@ -9,7 +9,7 @@
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devfile_registry
package devfileregistry
import (
"github.com/eclipse-che/che-operator/pkg/deploy"
@ -19,39 +19,34 @@ import (
v1 "k8s.io/api/core/v1"
)
func SyncDevfileRegistryDeploymentToCluster(deployContext *deploy.DeployContext) (bool, error) {
specDeployment := GetDevfileRegistrySpecDeployment(deployContext)
return deploy.SyncDeploymentSpecToCluster(deployContext, specDeployment, deploy.DefaultDeploymentDiffOpts)
}
func GetDevfileRegistrySpecDeployment(deployContext *deploy.DeployContext) *appsv1.Deployment {
func (p *DevfileRegistry) GetDevfileRegistryDeploymentSpec() *appsv1.Deployment {
registryType := "devfile"
registryImage := util.GetValue(deployContext.CheCluster.Spec.Server.DevfileRegistryImage, deploy.DefaultDevfileRegistryImage(deployContext.CheCluster))
registryImagePullPolicy := v1.PullPolicy(util.GetValue(string(deployContext.CheCluster.Spec.Server.DevfileRegistryPullPolicy), deploy.DefaultPullPolicyFromDockerImage(registryImage)))
registryImage := util.GetValue(p.deployContext.CheCluster.Spec.Server.DevfileRegistryImage, deploy.DefaultDevfileRegistryImage(p.deployContext.CheCluster))
registryImagePullPolicy := v1.PullPolicy(util.GetValue(string(p.deployContext.CheCluster.Spec.Server.DevfileRegistryPullPolicy), deploy.DefaultPullPolicyFromDockerImage(registryImage)))
probePath := "/devfiles/"
devfileImagesEnv := util.GetEnvByRegExp("^.*devfile_registry_image.*$")
resources := v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceMemory: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.DevfileRegistryMemoryRequest,
p.deployContext.CheCluster.Spec.Server.DevfileRegistryMemoryRequest,
deploy.DefaultDevfileRegistryMemoryRequest),
v1.ResourceCPU: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.DevfileRegistryCpuRequest,
p.deployContext.CheCluster.Spec.Server.DevfileRegistryCpuRequest,
deploy.DefaultDevfileRegistryCpuRequest),
},
Limits: v1.ResourceList{
v1.ResourceMemory: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.DevfileRegistryMemoryLimit,
p.deployContext.CheCluster.Spec.Server.DevfileRegistryMemoryLimit,
deploy.DefaultDevfileRegistryMemoryLimit),
v1.ResourceCPU: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.DevfileRegistryCpuLimit,
p.deployContext.CheCluster.Spec.Server.DevfileRegistryCpuLimit,
deploy.DefaultDevfileRegistryCpuLimit),
},
}
return registry.GetSpecRegistryDeployment(
deployContext,
p.deployContext,
registryType,
registryImage,
devfileImagesEnv,

View File

@ -9,7 +9,7 @@
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devfile_registry
package devfileregistry
import (
"os"
@ -29,7 +29,7 @@ import (
"testing"
)
func TestDeployment(t *testing.T) {
func TestGetDevfileRegistryDeploymentSpec(t *testing.T) {
type testCase struct {
name string
initObjects []runtime.Object
@ -93,7 +93,8 @@ func TestDeployment(t *testing.T) {
CheCluster: testCase.cheCluster,
}
deployment := GetDevfileRegistrySpecDeployment(deployContext)
devfileregistry := NewDevfileRegistry(deployContext)
deployment := devfileregistry.GetDevfileRegistryDeploymentSpec()
util.CompareResources(deployment,
util.TestExpectedResources{

View File

@ -0,0 +1,92 @@
//
// Copyright (c) 2012-2019 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devfileregistry
import (
"context"
"github.com/eclipse-che/che-operator/pkg/deploy"
"github.com/eclipse-che/che-operator/pkg/util"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
routev1 "github.com/openshift/api/route/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"testing"
)
func TestDevfileRegistrySyncAll(t *testing.T) {
cheCluster := &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
}
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
corev1.SchemeBuilder.AddToScheme(scheme.Scheme)
routev1.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme, cheCluster)
deployContext := &deploy.DeployContext{
CheCluster: cheCluster,
ClusterAPI: deploy.ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
util.IsOpenShift = true
devfileregistry := NewDevfileRegistry(deployContext)
done, err := devfileregistry.SyncAll()
if !done || err != nil {
t.Fatalf("Failed to sync Devfile Registry: %v", err)
}
// check service
service := &corev1.Service{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, service)
if err != nil {
t.Fatalf("Service not found: %v", err)
}
// check endpoint
route := &routev1.Route{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, route)
if err != nil {
t.Fatalf("Route not found: %v", err)
}
// check configmap
cm := &corev1.ConfigMap{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, cm)
if err != nil {
t.Fatalf("Config Map not found: %v", err)
}
// check deployment
deployment := &appsv1.Deployment{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "devfile-registry", Namespace: "eclipse-che"}, deployment)
if err != nil {
t.Fatalf("Deployment not found: %v", err)
}
if cheCluster.Status.DevfileRegistryURL == "" {
t.Fatalf("Status wasn't updated")
}
}

View File

@ -9,7 +9,7 @@
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package plugin_registry
package devfileregistry
import "github.com/eclipse-che/che-operator/pkg/deploy"

View File

@ -13,7 +13,6 @@ package identity_provider
import (
"errors"
"fmt"
"strings"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
@ -88,8 +87,6 @@ func syncExposure(deployContext *deploy.DeployContext) (bool, error) {
}
keycloakURL := protocol + "://" + endpoint
deployContext.InternalService.KeycloakHost = fmt.Sprintf("%s://%s.%s.svc:%d/auth", "http", deploy.IdentityProviderName, cr.Namespace, 8080)
if cr.Spec.Auth.IdentityProviderURL != keycloakURL {
cr.Spec.Auth.IdentityProviderURL = keycloakURL
if err := deploy.UpdateCheCRSpec(deployContext, "Keycloak URL", keycloakURL); err != nil {

View File

@ -1,121 +0,0 @@
//
// Copyright (c) 2012-2019 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package plugin_registry
import (
"encoding/json"
"fmt"
"strings"
"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/sirupsen/logrus"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
)
type PluginRegistryConfigMap struct {
CheSidecarContainersRegistryURL string `json:"CHE_SIDECAR_CONTAINERS_REGISTRY_URL"`
CheSidecarContainersRegistryOrganization string `json:"CHE_SIDECAR_CONTAINERS_REGISTRY_ORGANIZATION"`
}
/**
* Create plugin registry resources unless an external registry is used.
*/
func SyncPluginRegistryToCluster(deployContext *deploy.DeployContext) (bool, error) {
pluginRegistryURL := deployContext.CheCluster.Spec.Server.PluginRegistryUrl
if !deployContext.CheCluster.Spec.Server.ExternalPluginRegistry {
endpoint, done, err := expose.Expose(
deployContext,
deploy.PluginRegistryName,
deployContext.CheCluster.Spec.Server.PluginRegistryRoute,
deployContext.CheCluster.Spec.Server.PluginRegistryIngress)
if !done {
return false, err
}
if pluginRegistryURL == "" {
if deployContext.CheCluster.Spec.Server.TlsSupport {
pluginRegistryURL = "https://" + endpoint
} else {
pluginRegistryURL = "http://" + endpoint
}
// append the API version to plugin registry
if !strings.HasSuffix(pluginRegistryURL, "/") {
pluginRegistryURL = pluginRegistryURL + "/v3"
} else {
pluginRegistryURL = pluginRegistryURL + "v3"
}
}
if deployContext.CheCluster.IsAirGapMode() {
configMapData := getPluginRegistryConfigMapData(deployContext.CheCluster)
done, err := deploy.SyncConfigMapDataToCluster(deployContext, deploy.PluginRegistryName, configMapData, deploy.PluginRegistryName)
if !done {
return false, err
}
}
// Create a new registry service
done, err = deploy.SyncServiceToCluster(deployContext, deploy.PluginRegistryName, []string{"http"}, []int32{8080}, deploy.PluginRegistryName)
if !done {
if err != nil {
logrus.Error(err)
}
return false, err
}
deployContext.InternalService.PluginRegistryHost = fmt.Sprintf("http://%s.%s.svc:8080/v3", deploy.PluginRegistryName, deployContext.CheCluster.Namespace)
// Deploy plugin registry
provisioned, err := SyncPluginRegistryDeploymentToCluster(deployContext)
if !util.IsTestMode() {
if !provisioned {
logrus.Info("Waiting on deployment '" + deploy.PluginRegistryName + "' to be ready")
if err != nil {
logrus.Error(err)
}
return provisioned, err
}
}
}
if pluginRegistryURL != deployContext.CheCluster.Status.PluginRegistryURL {
deployContext.CheCluster.Status.PluginRegistryURL = pluginRegistryURL
if err := deploy.UpdateCheCRStatus(deployContext, "status: Plugin Registry URL", pluginRegistryURL); err != nil {
return false, err
}
}
return true, nil
}
func getPluginRegistryConfigMapData(cr *orgv1.CheCluster) map[string]string {
pluginRegistryEnv := make(map[string]string)
data := &PluginRegistryConfigMap{
CheSidecarContainersRegistryURL: cr.Spec.Server.AirGapContainerRegistryHostname,
CheSidecarContainersRegistryOrganization: cr.Spec.Server.AirGapContainerRegistryOrganization,
}
out, err := json.Marshal(data)
if err != nil {
fmt.Println(err)
}
err = json.Unmarshal(out, &pluginRegistryEnv)
if err != nil {
fmt.Println(err)
}
return pluginRegistryEnv
}

View File

@ -9,7 +9,7 @@
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devfile_registry
package pluginregistry
import "github.com/eclipse-che/che-operator/pkg/deploy"

View File

@ -0,0 +1,121 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package pluginregistry
import (
"strings"
"github.com/eclipse-che/che-operator/pkg/deploy"
"github.com/eclipse-che/che-operator/pkg/deploy/expose"
corev1 "k8s.io/api/core/v1"
)
type PluginRegistry struct {
deployContext *deploy.DeployContext
}
func NewPluginRegistry(deployContext *deploy.DeployContext) *PluginRegistry {
return &PluginRegistry{
deployContext: deployContext,
}
}
func (p *PluginRegistry) SyncAll() (bool, error) {
done, err := p.SyncService()
if !done {
return false, err
}
endpoint, done, err := p.ExposeEndpoint()
if !done {
return false, err
}
done, err = p.UpdateStatus(endpoint)
if !done {
return false, err
}
if p.deployContext.CheCluster.IsAirGapMode() {
done, err := p.SyncConfigMap()
if !done {
return false, err
}
} else {
done, err := deploy.DeleteNamespacedObject(p.deployContext, deploy.PluginRegistryName, &corev1.ConfigMap{})
if !done {
return false, err
}
}
done, err = p.SyncDeployment()
if !done {
return false, err
}
return true, nil
}
func (p *PluginRegistry) SyncService() (bool, error) {
return deploy.SyncServiceToCluster(
p.deployContext,
deploy.PluginRegistryName,
[]string{"http"},
[]int32{8080},
deploy.PluginRegistryName)
}
func (p *PluginRegistry) SyncConfigMap() (bool, error) {
data, err := p.GetConfigMapData()
if err != nil {
return false, err
}
return deploy.SyncConfigMapDataToCluster(p.deployContext, deploy.PluginRegistryName, data, deploy.PluginRegistryName)
}
func (p *PluginRegistry) ExposeEndpoint() (string, bool, error) {
return expose.Expose(
p.deployContext,
deploy.PluginRegistryName,
p.deployContext.CheCluster.Spec.Server.PluginRegistryRoute,
p.deployContext.CheCluster.Spec.Server.PluginRegistryIngress)
}
func (p *PluginRegistry) UpdateStatus(endpoint string) (bool, error) {
var pluginRegistryURL string
if p.deployContext.CheCluster.Spec.Server.TlsSupport {
pluginRegistryURL = "https://" + endpoint
} else {
pluginRegistryURL = "http://" + endpoint
}
// append the API version to plugin registry
if !strings.HasSuffix(pluginRegistryURL, "/") {
pluginRegistryURL = pluginRegistryURL + "/v3"
} else {
pluginRegistryURL = pluginRegistryURL + "v3"
}
if pluginRegistryURL != p.deployContext.CheCluster.Status.PluginRegistryURL {
p.deployContext.CheCluster.Status.PluginRegistryURL = pluginRegistryURL
if err := deploy.UpdateCheCRStatus(p.deployContext, "status: Plugin Registry URL", pluginRegistryURL); err != nil {
return false, err
}
}
return true, nil
}
func (p *PluginRegistry) SyncDeployment() (bool, error) {
spec := p.GetPluginRegistryDeploymentSpec()
return deploy.SyncDeploymentSpecToCluster(p.deployContext, spec, deploy.DefaultDeploymentDiffOpts)
}

View File

@ -0,0 +1,41 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package pluginregistry
import (
"encoding/json"
)
type PluginRegistryConfigMap struct {
CheSidecarContainersRegistryURL string `json:"CHE_SIDECAR_CONTAINERS_REGISTRY_URL"`
CheSidecarContainersRegistryOrganization string `json:"CHE_SIDECAR_CONTAINERS_REGISTRY_ORGANIZATION"`
}
func (p *PluginRegistry) GetConfigMapData() (map[string]string, error) {
pluginRegistryEnv := make(map[string]string)
data := &PluginRegistryConfigMap{
CheSidecarContainersRegistryURL: p.deployContext.CheCluster.Spec.Server.AirGapContainerRegistryHostname,
CheSidecarContainersRegistryOrganization: p.deployContext.CheCluster.Spec.Server.AirGapContainerRegistryOrganization,
}
out, err := json.Marshal(data)
if err != nil {
return nil, err
}
err = json.Unmarshal(out, &pluginRegistryEnv)
if err != nil {
return nil, err
}
return pluginRegistryEnv, nil
}

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2012-2019 Red Hat, Inc.
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
@ -9,7 +9,7 @@
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package plugin_registry
package pluginregistry
import (
"github.com/eclipse-che/che-operator/pkg/deploy"
@ -19,39 +19,34 @@ import (
corev1 "k8s.io/api/core/v1"
)
func SyncPluginRegistryDeploymentToCluster(deployContext *deploy.DeployContext) (bool, error) {
specDeployment := GetPluginRegistrySpecDeployment(deployContext)
return deploy.SyncDeploymentSpecToCluster(deployContext, specDeployment, deploy.DefaultDeploymentDiffOpts)
}
func GetPluginRegistrySpecDeployment(deployContext *deploy.DeployContext) *appsv1.Deployment {
func (p *PluginRegistry) GetPluginRegistryDeploymentSpec() *appsv1.Deployment {
registryType := "plugin"
registryImage := util.GetValue(deployContext.CheCluster.Spec.Server.PluginRegistryImage, deploy.DefaultPluginRegistryImage(deployContext.CheCluster))
registryImagePullPolicy := corev1.PullPolicy(util.GetValue(string(deployContext.CheCluster.Spec.Server.PluginRegistryPullPolicy), deploy.DefaultPullPolicyFromDockerImage(registryImage)))
registryImage := util.GetValue(p.deployContext.CheCluster.Spec.Server.PluginRegistryImage, deploy.DefaultPluginRegistryImage(p.deployContext.CheCluster))
registryImagePullPolicy := corev1.PullPolicy(util.GetValue(string(p.deployContext.CheCluster.Spec.Server.PluginRegistryPullPolicy), deploy.DefaultPullPolicyFromDockerImage(registryImage)))
probePath := "/v3/plugins/"
pluginImagesEnv := util.GetEnvByRegExp("^.*plugin_registry_image.*$")
resources := corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.PluginRegistryMemoryRequest,
p.deployContext.CheCluster.Spec.Server.PluginRegistryMemoryRequest,
deploy.DefaultPluginRegistryMemoryRequest),
corev1.ResourceCPU: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.PluginRegistryCpuRequest,
p.deployContext.CheCluster.Spec.Server.PluginRegistryCpuRequest,
deploy.DefaultPluginRegistryCpuRequest),
},
Limits: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.PluginRegistryMemoryLimit,
p.deployContext.CheCluster.Spec.Server.PluginRegistryMemoryLimit,
deploy.DefaultPluginRegistryMemoryLimit),
corev1.ResourceCPU: util.GetResourceQuantity(
deployContext.CheCluster.Spec.Server.PluginRegistryCpuLimit,
p.deployContext.CheCluster.Spec.Server.PluginRegistryCpuLimit,
deploy.DefaultPluginRegistryCpuLimit),
},
}
return registry.GetSpecRegistryDeployment(
deployContext,
p.deployContext,
registryType,
registryImage,
pluginImagesEnv,

View File

@ -9,7 +9,7 @@
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package plugin_registry
package pluginregistry
import (
"os"
@ -29,7 +29,7 @@ import (
"testing"
)
func TestDeployment(t *testing.T) {
func TestGetPluginRegistryDeploymentSpec(t *testing.T) {
type testCase struct {
name string
initObjects []runtime.Object
@ -93,7 +93,8 @@ func TestDeployment(t *testing.T) {
Proxy: &deploy.Proxy{},
}
deployment := GetPluginRegistrySpecDeployment(deployContext)
pluginregistry := NewPluginRegistry(deployContext)
deployment := pluginregistry.GetPluginRegistryDeploymentSpec()
util.CompareResources(deployment,
util.TestExpectedResources{

View File

@ -0,0 +1,85 @@
//
// 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 pluginregistry
import (
"context"
"github.com/eclipse-che/che-operator/pkg/deploy"
"github.com/eclipse-che/che-operator/pkg/util"
orgv1 "github.com/eclipse-che/che-operator/pkg/apis/org/v1"
routev1 "github.com/openshift/api/route/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"testing"
)
func TestPluginRegistrySyncAll(t *testing.T) {
cheCluster := &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
Name: "eclipse-che",
},
}
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
corev1.SchemeBuilder.AddToScheme(scheme.Scheme)
routev1.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme, cheCluster)
deployContext := &deploy.DeployContext{
CheCluster: cheCluster,
ClusterAPI: deploy.ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
util.IsOpenShift = true
pluginregistry := NewPluginRegistry(deployContext)
done, err := pluginregistry.SyncAll()
if !done || err != nil {
t.Fatalf("Failed to sync Plugin Registry: %v", err)
}
// check service
service := &corev1.Service{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "plugin-registry", Namespace: "eclipse-che"}, service)
if err != nil {
t.Fatalf("Service not found: %v", err)
}
// check endpoint
route := &routev1.Route{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "plugin-registry", Namespace: "eclipse-che"}, route)
if err != nil {
t.Fatalf("Route not found: %v", err)
}
// check deployment
deployment := &appsv1.Deployment{}
err = cli.Get(context.TODO(), types.NamespacedName{Name: "plugin-registry", Namespace: "eclipse-che"}, deployment)
if err != nil {
t.Fatalf("Deployment not found: %v", err)
}
if cheCluster.Status.PluginRegistryURL == "" {
t.Fatalf("Status wasn't updated")
}
}

View File

@ -21,12 +21,6 @@ import (
"github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
var (
postgresAdminPassword = util.GeneratePasswd(12)
)
type Postgres struct {
@ -41,29 +35,25 @@ func NewPostgres(deployContext *deploy.DeployContext) *Postgres {
}
}
func (p *Postgres) Sync() (bool, error) {
if p.deployContext.CheCluster.Spec.Database.ExternalDb {
return true, nil
}
done, err := p.syncService()
func (p *Postgres) SyncAll() (bool, error) {
done, err := p.SyncService()
if !done {
return false, err
}
done, err = p.syncPVC()
done, err = p.SyncPVC()
if !done {
return false, err
}
done, err = p.syncDeployment()
done, err = p.SyncDeployment()
if !done {
return false, err
}
if !p.deployContext.CheCluster.Status.DbProvisoned {
if !util.IsTestMode() { // ignore in tests
done, err = p.provisionDB()
done, err = p.ProvisionDB()
if !done {
return false, err
}
@ -73,14 +63,14 @@ func (p *Postgres) Sync() (bool, error) {
return true, nil
}
func (p *Postgres) syncService() (bool, error) {
func (p *Postgres) SyncService() (bool, error) {
if !p.isMultiUser {
return deploy.DeleteNamespacedObject(p.deployContext, deploy.PostgresName, &corev1.Service{})
}
return deploy.SyncServiceToCluster(p.deployContext, deploy.PostgresName, []string{deploy.PostgresName}, []int32{5432}, deploy.PostgresName)
}
func (p *Postgres) syncPVC() (bool, error) {
func (p *Postgres) SyncPVC() (bool, error) {
if !p.isMultiUser {
return deploy.DeleteNamespacedObject(p.deployContext, deploy.DefaultPostgresVolumeClaimName, &corev1.PersistentVolumeClaim{})
}
@ -92,7 +82,7 @@ func (p *Postgres) syncPVC() (bool, error) {
return done, err
}
func (p *Postgres) syncDeployment() (bool, error) {
func (p *Postgres) SyncDeployment() (bool, error) {
if !p.isMultiUser {
return deploy.DeleteNamespacedObject(p.deployContext, deploy.PostgresName, &appsv1.Deployment{})
}
@ -107,7 +97,7 @@ func (p *Postgres) syncDeployment() (bool, error) {
clusterDeployment = nil
}
specDeployment, err := p.getDeploymentSpec(clusterDeployment)
specDeployment, err := p.GetDeploymentSpec(clusterDeployment)
if err != nil {
return false, err
}
@ -115,7 +105,7 @@ func (p *Postgres) syncDeployment() (bool, error) {
return deploy.SyncDeploymentSpecToCluster(p.deployContext, specDeployment, deploy.DefaultDeploymentDiffOpts)
}
func (p *Postgres) provisionDB() (bool, error) {
func (p *Postgres) ProvisionDB() (bool, error) {
identityProviderPostgresPassword := p.deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresPassword
identityProviderPostgresSecret := p.deployContext.CheCluster.Spec.Auth.IdentityProviderPostgresSecret
if identityProviderPostgresSecret != "" {
@ -148,184 +138,3 @@ func (p *Postgres) provisionDB() (bool, error) {
return true, nil
}
func (p *Postgres) getDeploymentSpec(clusterDeployment *appsv1.Deployment) (*appsv1.Deployment, error) {
terminationGracePeriodSeconds := int64(30)
labels, labelSelector := deploy.GetLabelsAndSelector(p.deployContext.CheCluster, deploy.PostgresName)
chePostgresDb := util.GetValue(p.deployContext.CheCluster.Spec.Database.ChePostgresDb, "dbche")
postgresImage := util.GetValue(p.deployContext.CheCluster.Spec.Database.PostgresImage, deploy.DefaultPostgresImage(p.deployContext.CheCluster))
pullPolicy := corev1.PullPolicy(util.GetValue(string(p.deployContext.CheCluster.Spec.Database.PostgresImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(postgresImage)))
if clusterDeployment != nil {
clusterContainer := &clusterDeployment.Spec.Template.Spec.Containers[0]
env := util.FindEnv(clusterContainer.Env, "POSTGRESQL_ADMIN_PASSWORD")
if env != nil {
postgresAdminPassword = env.Value
}
}
deployment := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: deploy.PostgresName,
Namespace: p.deployContext.CheCluster.Namespace,
Labels: labels,
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{MatchLabels: labelSelector},
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.DeploymentStrategyType("Recreate"),
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
Volumes: []corev1.Volume{
{
Name: deploy.DefaultPostgresVolumeClaimName,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: deploy.DefaultPostgresVolumeClaimName,
},
},
},
},
Containers: []corev1.Container{
{
Name: deploy.PostgresName,
Image: postgresImage,
ImagePullPolicy: pullPolicy,
Ports: []corev1.ContainerPort{
{
Name: deploy.PostgresName,
ContainerPort: 5432,
Protocol: "TCP",
},
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Memory,
deploy.DefaultPostgresMemoryRequest),
corev1.ResourceCPU: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Cpu,
deploy.DefaultPostgresCpuRequest),
},
Limits: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Memory,
deploy.DefaultPostgresMemoryLimit),
corev1.ResourceCPU: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Cpu,
deploy.DefaultPostgresCpuLimit),
},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: deploy.DefaultPostgresVolumeClaimName,
MountPath: "/var/lib/pgsql/data",
},
},
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
Exec: &corev1.ExecAction{
Command: []string{
"/bin/sh",
"-i",
"-c",
"psql -h 127.0.0.1 -U $POSTGRESQL_USER -q -d " + chePostgresDb + " -c 'SELECT 1'",
},
},
},
InitialDelaySeconds: 15,
FailureThreshold: 10,
SuccessThreshold: 1,
PeriodSeconds: 10,
TimeoutSeconds: 5,
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
TCPSocket: &corev1.TCPSocketAction{
Port: intstr.FromInt(5432),
},
},
InitialDelaySeconds: 30,
FailureThreshold: 10,
SuccessThreshold: 1,
PeriodSeconds: 10,
TimeoutSeconds: 5,
},
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
Env: []corev1.EnvVar{
{
Name: "POSTGRESQL_DATABASE",
Value: chePostgresDb,
},
{
Name: "POSTGRESQL_ADMIN_PASSWORD",
Value: postgresAdminPassword,
},
}},
},
TerminationGracePeriodSeconds: &terminationGracePeriodSeconds,
RestartPolicy: "Always",
},
},
},
}
container := &deployment.Spec.Template.Spec.Containers[0]
chePostgresSecret := p.deployContext.CheCluster.Spec.Database.ChePostgresSecret
if len(chePostgresSecret) > 0 {
container.Env = append(container.Env,
corev1.EnvVar{
Name: "POSTGRESQL_USER",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
Key: "user",
LocalObjectReference: corev1.LocalObjectReference{
Name: chePostgresSecret,
},
},
},
}, corev1.EnvVar{
Name: "POSTGRESQL_PASSWORD",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
Key: "password",
LocalObjectReference: corev1.LocalObjectReference{
Name: chePostgresSecret,
},
},
},
})
} else {
container.Env = append(container.Env,
corev1.EnvVar{
Name: "POSTGRESQL_USER",
Value: p.deployContext.CheCluster.Spec.Database.ChePostgresUser,
}, corev1.EnvVar{
Name: "POSTGRESQL_PASSWORD",
Value: p.deployContext.CheCluster.Spec.Database.ChePostgresPassword,
})
}
if !util.IsOpenShift {
var runAsUser int64 = 26
deployment.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{
RunAsUser: &runAsUser,
FSGroup: &runAsUser,
}
}
return deployment, nil
}

View File

@ -0,0 +1,206 @@
//
// 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 postgres
import (
"github.com/eclipse-che/che-operator/pkg/deploy"
"github.com/eclipse-che/che-operator/pkg/util"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
var (
postgresAdminPassword = util.GeneratePasswd(12)
)
func (p *Postgres) GetDeploymentSpec(clusterDeployment *appsv1.Deployment) (*appsv1.Deployment, error) {
terminationGracePeriodSeconds := int64(30)
labels, labelSelector := deploy.GetLabelsAndSelector(p.deployContext.CheCluster, deploy.PostgresName)
chePostgresDb := util.GetValue(p.deployContext.CheCluster.Spec.Database.ChePostgresDb, "dbche")
postgresImage := util.GetValue(p.deployContext.CheCluster.Spec.Database.PostgresImage, deploy.DefaultPostgresImage(p.deployContext.CheCluster))
pullPolicy := corev1.PullPolicy(util.GetValue(string(p.deployContext.CheCluster.Spec.Database.PostgresImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(postgresImage)))
if clusterDeployment != nil {
clusterContainer := &clusterDeployment.Spec.Template.Spec.Containers[0]
env := util.FindEnv(clusterContainer.Env, "POSTGRESQL_ADMIN_PASSWORD")
if env != nil {
postgresAdminPassword = env.Value
}
}
deployment := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: deploy.PostgresName,
Namespace: p.deployContext.CheCluster.Namespace,
Labels: labels,
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{MatchLabels: labelSelector},
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.DeploymentStrategyType("Recreate"),
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
Volumes: []corev1.Volume{
{
Name: deploy.DefaultPostgresVolumeClaimName,
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: deploy.DefaultPostgresVolumeClaimName,
},
},
},
},
Containers: []corev1.Container{
{
Name: deploy.PostgresName,
Image: postgresImage,
ImagePullPolicy: pullPolicy,
Ports: []corev1.ContainerPort{
{
Name: deploy.PostgresName,
ContainerPort: 5432,
Protocol: "TCP",
},
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Memory,
deploy.DefaultPostgresMemoryRequest),
corev1.ResourceCPU: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Requests.Cpu,
deploy.DefaultPostgresCpuRequest),
},
Limits: corev1.ResourceList{
corev1.ResourceMemory: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Memory,
deploy.DefaultPostgresMemoryLimit),
corev1.ResourceCPU: util.GetResourceQuantity(
p.deployContext.CheCluster.Spec.Database.ChePostgresContainerResources.Limits.Cpu,
deploy.DefaultPostgresCpuLimit),
},
},
VolumeMounts: []corev1.VolumeMount{
{
Name: deploy.DefaultPostgresVolumeClaimName,
MountPath: "/var/lib/pgsql/data",
},
},
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
Exec: &corev1.ExecAction{
Command: []string{
"/bin/sh",
"-i",
"-c",
"psql -h 127.0.0.1 -U $POSTGRESQL_USER -q -d " + chePostgresDb + " -c 'SELECT 1'",
},
},
},
InitialDelaySeconds: 15,
FailureThreshold: 10,
SuccessThreshold: 1,
PeriodSeconds: 10,
TimeoutSeconds: 5,
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
TCPSocket: &corev1.TCPSocketAction{
Port: intstr.FromInt(5432),
},
},
InitialDelaySeconds: 30,
FailureThreshold: 10,
SuccessThreshold: 1,
PeriodSeconds: 10,
TimeoutSeconds: 5,
},
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
Env: []corev1.EnvVar{
{
Name: "POSTGRESQL_DATABASE",
Value: chePostgresDb,
},
{
Name: "POSTGRESQL_ADMIN_PASSWORD",
Value: postgresAdminPassword,
},
}},
},
TerminationGracePeriodSeconds: &terminationGracePeriodSeconds,
RestartPolicy: "Always",
},
},
},
}
container := &deployment.Spec.Template.Spec.Containers[0]
chePostgresSecret := p.deployContext.CheCluster.Spec.Database.ChePostgresSecret
if len(chePostgresSecret) > 0 {
container.Env = append(container.Env,
corev1.EnvVar{
Name: "POSTGRESQL_USER",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
Key: "user",
LocalObjectReference: corev1.LocalObjectReference{
Name: chePostgresSecret,
},
},
},
}, corev1.EnvVar{
Name: "POSTGRESQL_PASSWORD",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
Key: "password",
LocalObjectReference: corev1.LocalObjectReference{
Name: chePostgresSecret,
},
},
},
})
} else {
container.Env = append(container.Env,
corev1.EnvVar{
Name: "POSTGRESQL_USER",
Value: p.deployContext.CheCluster.Spec.Database.ChePostgresUser,
}, corev1.EnvVar{
Name: "POSTGRESQL_PASSWORD",
Value: p.deployContext.CheCluster.Spec.Database.ChePostgresPassword,
})
}
if !util.IsOpenShift {
var runAsUser int64 = 26
deployment.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{
RunAsUser: &runAsUser,
FSGroup: &runAsUser,
}
}
return deployment, nil
}

View File

@ -33,7 +33,7 @@ import (
"testing"
)
func TestDeployment(t *testing.T) {
func TestDeploymentSpec(t *testing.T) {
type testCase struct {
name string
initObjects []runtime.Object
@ -104,7 +104,7 @@ func TestDeployment(t *testing.T) {
}
postgres := NewPostgres(deployContext)
deployment, err := postgres.getDeploymentSpec(nil)
deployment, err := postgres.GetDeploymentSpec(nil)
if err != nil {
t.Fatalf("Error creating deployment: %v", err)
}
@ -123,7 +123,7 @@ func TestDeployment(t *testing.T) {
}
}
func TestSyncPostgresToCluster(t *testing.T) {
func TestSyncAllToCluster(t *testing.T) {
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
corev1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
@ -142,7 +142,7 @@ func TestSyncPostgresToCluster(t *testing.T) {
}
postgres := NewPostgres(deployContext)
done, err := postgres.Sync()
done, err := postgres.SyncAll()
if !done || err != nil {
t.Fatalf("Failed to sync PostgreSQL: %v", err)
}

View File

@ -13,9 +13,9 @@ package registry
import (
"github.com/eclipse-che/che-operator/pkg/deploy"
v12 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
v13 "k8s.io/apimachinery/pkg/apis/meta/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/util/intstr"
)
@ -23,10 +23,10 @@ func GetSpecRegistryDeployment(
deployContext *deploy.DeployContext,
registryType string,
registryImage string,
env []v1.EnvVar,
registryImagePullPolicy v1.PullPolicy,
resources v1.ResourceRequirements,
probePath string) *v12.Deployment {
env []corev1.EnvVar,
registryImagePullPolicy corev1.PullPolicy,
resources corev1.ResourceRequirements,
probePath string) *appsv1.Deployment {
terminationGracePeriodSeconds := int64(30)
name := registryType + "-registry"
@ -35,38 +35,38 @@ func GetSpecRegistryDeployment(
_1 := int32(1)
_2 := int32(2)
isOptional := true
deployment := &v12.Deployment{
TypeMeta: v13.TypeMeta{
deployment := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: v13.ObjectMeta{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: deployContext.CheCluster.Namespace,
Labels: labels,
},
Spec: v12.DeploymentSpec{
Spec: appsv1.DeploymentSpec{
Replicas: &_1,
RevisionHistoryLimit: &_2,
Selector: &v13.LabelSelector{MatchLabels: labelSelector},
Strategy: v12.DeploymentStrategy{
Type: v12.RollingUpdateDeploymentStrategyType,
RollingUpdate: &v12.RollingUpdateDeployment{
Selector: &metav1.LabelSelector{MatchLabels: labelSelector},
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &_25Percent,
MaxUnavailable: &_25Percent,
},
},
Template: v1.PodTemplateSpec{
ObjectMeta: v13.ObjectMeta{
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: v1.PodSpec{
Containers: []v1.Container{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "che-" + name,
Image: registryImage,
ImagePullPolicy: registryImagePullPolicy,
Ports: []v1.ContainerPort{
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 8080,
@ -74,26 +74,26 @@ func GetSpecRegistryDeployment(
},
},
Env: env,
EnvFrom: []v1.EnvFromSource{
EnvFrom: []corev1.EnvFromSource{
{
ConfigMapRef: &v1.ConfigMapEnvSource{
ConfigMapRef: &corev1.ConfigMapEnvSource{
Optional: &isOptional,
LocalObjectReference: v1.LocalObjectReference{
LocalObjectReference: corev1.LocalObjectReference{
Name: registryType + "-registry",
},
},
},
},
Resources: resources,
ReadinessProbe: &v1.Probe{
Handler: v1.Handler{
HTTPGet: &v1.HTTPGetAction{
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/" + registryType + "s/",
Port: intstr.IntOrString{
Type: intstr.Int,
IntVal: int32(8080),
},
Scheme: v1.URISchemeHTTP,
Scheme: corev1.URISchemeHTTP,
},
},
InitialDelaySeconds: 3,
@ -102,15 +102,15 @@ func GetSpecRegistryDeployment(
SuccessThreshold: 1,
PeriodSeconds: 10,
},
LivenessProbe: &v1.Probe{
Handler: v1.Handler{
HTTPGet: &v1.HTTPGetAction{
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/" + registryType + "s/",
Port: intstr.IntOrString{
Type: intstr.Int,
IntVal: int32(8080),
},
Scheme: v1.URISchemeHTTP,
Scheme: corev1.URISchemeHTTP,
},
},
InitialDelaySeconds: 30,
@ -119,9 +119,9 @@ func GetSpecRegistryDeployment(
SuccessThreshold: 1,
PeriodSeconds: 10,
},
SecurityContext: &v1.SecurityContext{
Capabilities: &v1.Capabilities{
Drop: []v1.Capability{"ALL"},
SecurityContext: &corev1.SecurityContext{
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"},
},
},
},

View File

@ -14,7 +14,6 @@ package server
import (
"encoding/json"
"fmt"
"net/url"
"os"
"strconv"
@ -175,33 +174,27 @@ func GetCheConfigMapData(deployContext *deploy.DeployContext) (cheEnv map[string
var keycloakInternalURL, pluginRegistryInternalURL, devfileRegistryInternalURL, cheInternalAPI, webSocketEndpoint, webSocketEndpointMinor string
if deployContext.CheCluster.Spec.Server.UseInternalClusterSVCNames && !deployContext.CheCluster.Spec.Auth.ExternalIdentityProvider {
keycloakInternalURL = deployContext.InternalService.KeycloakHost
keycloakInternalURL = fmt.Sprintf("%s://%s.%s.svc:8080/auth", "http", deploy.IdentityProviderName, deployContext.CheCluster.Namespace)
} else {
keycloakInternalURL = keycloakURL
}
if deployContext.CheCluster.Spec.Server.UseInternalClusterSVCNames && !deployContext.CheCluster.Spec.Server.ExternalDevfileRegistry {
devfileRegistryInternalURL = deployContext.InternalService.DevfileRegistryHost
devfileRegistryInternalURL = fmt.Sprintf("http://%s.%s.svc:8080", deploy.DevfileRegistryName, deployContext.CheCluster.Namespace)
} else {
devfileRegistryInternalURL = devfileRegistryURL
}
if deployContext.CheCluster.Spec.Server.UseInternalClusterSVCNames && !deployContext.CheCluster.Spec.Server.ExternalPluginRegistry {
pluginRegistryInternalURL = deployContext.InternalService.PluginRegistryHost
pluginRegistryInternalURL = fmt.Sprintf("http://%s.%s.svc:8080/v3", deploy.PluginRegistryName, deployContext.CheCluster.Namespace)
} else {
pluginRegistryInternalURL = pluginRegistryURL
}
if deployContext.CheCluster.Spec.Server.UseInternalClusterSVCNames {
cheInternalAPI = deployContext.InternalService.CheHost + "/api"
u, err := url.Parse(deployContext.InternalService.CheHost)
if err != nil {
return nil, err
}
webSocketEndpoint = "ws://" + u.Host + "/api/websocket"
webSocketEndpointMinor = "ws://" + u.Host + "/api/websocket-minor"
cheInternalAPI = fmt.Sprintf("http://%s.%s.svc:8080/api", deploy.CheServiceName, deployContext.CheCluster.Namespace)
webSocketEndpoint = fmt.Sprintf("ws://%s.%s.svc:8080/api/websocket", deploy.CheServiceName, deployContext.CheCluster.Namespace)
webSocketEndpointMinor = fmt.Sprintf("ws://%s.%s.svc:8080/api/websocket-minor", deploy.CheServiceName, deployContext.CheCluster.Namespace)
} else {
cheInternalAPI = cheAPI

View File

@ -102,13 +102,12 @@ func TestNewCheConfigMap(t *testing.T) {
func TestConfigMap(t *testing.T) {
type testCase struct {
name string
isOpenShift bool
isOpenShift4 bool
initObjects []runtime.Object
cheCluster *orgv1.CheCluster
internalService deploy.InternalService
expectedData map[string]string
name string
isOpenShift bool
isOpenShift4 bool
initObjects []runtime.Object
cheCluster *orgv1.CheCluster
expectedData map[string]string
}
testCases := []testCase{
@ -169,6 +168,10 @@ func TestConfigMap(t *testing.T) {
{
name: "Test k8s data, with internal cluster svc names",
cheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: "eclipse-che",
Namespace: "eclipse-che",
},
Spec: orgv1.CheClusterSpec{
Server: orgv1.CheClusterSpecServer{
CheHost: "che-host",
@ -176,17 +179,18 @@ func TestConfigMap(t *testing.T) {
},
},
},
internalService: deploy.InternalService{
CheHost: "http://che-host-internal.svc:8080",
},
expectedData: map[string]string{
"CHE_WEBSOCKET_ENDPOINT": "ws://che-host-internal.svc:8080/api/websocket",
"CHE_WEBSOCKET_ENDPOINT__MINOR": "ws://che-host-internal.svc:8080/api/websocket-minor",
"CHE_WEBSOCKET_ENDPOINT": "ws://che-host.eclipse-che.svc:8080/api/websocket",
"CHE_WEBSOCKET_ENDPOINT__MINOR": "ws://che-host.eclipse-che.svc:8080/api/websocket-minor",
},
},
{
name: "Test k8s data, without internal cluster svc names",
cheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Name: "eclipse-che",
Namespace: "eclipse-che",
},
Spec: orgv1.CheClusterSpec{
Server: orgv1.CheClusterSpecServer{
CheHost: "che-host",
@ -194,9 +198,6 @@ func TestConfigMap(t *testing.T) {
},
},
},
internalService: deploy.InternalService{
CheHost: "http://che-host-internal.svc:8080",
},
expectedData: map[string]string{
"CHE_WEBSOCKET_ENDPOINT": "ws://che-host/api/websocket",
"CHE_WEBSOCKET_ENDPOINT__MINOR": "ws://che-host/api/websocket-minor",
@ -213,8 +214,7 @@ func TestConfigMap(t *testing.T) {
nonCachedClient := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
deployContext := &deploy.DeployContext{
InternalService: testCase.internalService,
CheCluster: testCase.cheCluster,
CheCluster: testCase.cheCluster,
ClusterAPI: deploy.ClusterAPI{
Client: cli,
NonCachedClient: nonCachedClient,
@ -520,9 +520,6 @@ func TestShouldSetUpCorrectlyInternalDevfileRegistryServiceURL(t *testing.T) {
Scheme: scheme.Scheme,
},
Proxy: &deploy.Proxy{},
InternalService: deploy.InternalService{
DevfileRegistryHost: "http://devfile-registry.eclipse-che.svc:8080",
},
}
util.IsOpenShift = testCase.isOpenShift
@ -675,9 +672,6 @@ func TestShouldSetUpCorrectlyInternalPluginRegistryServiceURL(t *testing.T) {
Scheme: scheme.Scheme,
},
Proxy: &deploy.Proxy{},
InternalService: deploy.InternalService{
PluginRegistryHost: "http://plugin-registry.eclipse-che.svc:8080/v3",
},
}
util.IsOpenShift = testCase.isOpenShift
@ -770,9 +764,6 @@ func TestShouldSetUpCorrectlyInternalCheServerURL(t *testing.T) {
Scheme: scheme.Scheme,
},
Proxy: &deploy.Proxy{},
InternalService: deploy.InternalService{
CheHost: "http://che-host.eclipse-che.svc:8080",
},
}
util.IsOpenShift = testCase.isOpenShift
@ -920,9 +911,6 @@ func TestShouldSetUpCorrectlyInternalIdentityProviderServiceURL(t *testing.T) {
Scheme: scheme.Scheme,
},
Proxy: &deploy.Proxy{},
InternalService: deploy.InternalService{
KeycloakHost: "http://keycloak.eclipse-che.svc:8080/auth",
},
}
util.IsOpenShift = testCase.isOpenShift