Skip to content

Commit

Permalink
Run dashboard as separate deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
sleshchenko committed Feb 19, 2021
1 parent b4eff0a commit 063fb6d
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 24 deletions.
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,13 @@
"env": {
"MOCK_API": true,
"CHE_FLAVOR": "che"
},
}
},
{
"name": "Launch Main *.go File",
"type": "go",
"request": "launch",
"program": "${file}",
"program": "${file}"
},
{
"useApiV1": false,
Expand Down
8 changes: 4 additions & 4 deletions deploy/crds/org_v1_che_cr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ spec:
# use internal host names provided by cluster dns.
useInternalClusterSVCNames: true
# server image used in Che deployment
cheImage: ''
cheImage: 'sleshchenko/che-server'
# tag of an image used in Che deployment
cheImageTag: ''
cheImageTag: 'cut-dashboard'
# image:tag used in Devfile registry deployment
devfileRegistryImage: ''
# image:tag used in plugin registry deployment
Expand Down Expand Up @@ -55,9 +55,9 @@ spec:
# a list of non-proxy hosts. Use | as delimiter, eg localhost|my.host.com|123.42.12.32
nonProxyHosts: ''
# sets mem request for server deployment. Defaults to 512Mi
serverMemoryRequest: ''
serverMemoryRequest: '256Mi'
# sets mem limit for server deployment. Defaults to 1Gi
serverMemoryLimit: ''
serverMemoryLimit: '512Mi'
# sets default namespace where new workspaces will be created
workspaceNamespaceDefault: "<username>-che"
# defines if user is able to specify namespace different from the default
Expand Down
1 change: 1 addition & 0 deletions local-debug.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ echo "[WARN] Make sure that your CR contains valid ingress domain!"
operator-sdk run --local --watch-namespace ${CHE_NAMESPACE} --enable-delve &
OPERATOR_SDK_PID=$!


wait ${OPERATOR_SDK_PID}
13 changes: 13 additions & 0 deletions pkg/controller/che/che_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ package che
import (
"context"
"fmt"

"strconv"
"strings"
"time"

orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/eclipse/che-operator/pkg/deploy"
"github.com/eclipse/che-operator/pkg/deploy/dashboard"
devfile_registry "github.com/eclipse/che-operator/pkg/deploy/devfile-registry"
"github.com/eclipse/che-operator/pkg/deploy/gateway"
identity_provider "github.com/eclipse/che-operator/pkg/deploy/identity-provider"
Expand Down Expand Up @@ -899,6 +901,7 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}

provisioned, err = plugin_registry.SyncPluginRegistryToCluster(deployContext, cheHost)

if !tests {
if !provisioned {
if err != nil {
Expand All @@ -908,6 +911,16 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}

provisioned, err = dashboard.SyncDashboardToCluster(deployContext, cheHost)
if !tests {
if !provisioned {
if err != nil {
logrus.Errorf("Error provisioning '%s' to cluster: %v", dashboard.Dashboard, err)
}
return reconcile.Result{Requeue: true}, err
}
}

// create Che ConfigMap which is synced with CR and is not supposed to be manually edited
// controller will reconcile this CM with CR spec
cheConfigMap, err := server.SyncCheConfigMapToCluster(deployContext)
Expand Down
60 changes: 60 additions & 0 deletions pkg/deploy/dashboard/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// 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 dashboard

import (
"github.com/eclipse/che-operator/pkg/deploy"
"github.com/eclipse/che-operator/pkg/deploy/expose"
"github.com/eclipse/che-operator/pkg/util"
"github.com/sirupsen/logrus"
)

const (
Dashboard = "dashboard"
)

/**
* Create dashboard resources.
*/
func SyncDashboardToCluster(deployContext *deploy.DeployContext, cheHost string) (done bool, err error) {
// Deploy plugin registry
success, err := SyncDashboardDeploymentToCluster(deployContext)
if !util.IsTestMode() {
if !success {
logrus.Info("Waiting on deployment '" + Dashboard + "' to be ready")
if err != nil {
logrus.Error(err)
}

return false, err
}
}

// Create a new registry service
dashboardComponent := getDashboardComponent(deployContext)
dashboardLabels := deploy.GetLabels(deployContext.CheCluster, dashboardComponent)
serviceStatus := deploy.SyncServiceToCluster(deployContext, dashboardComponent, []string{"http"}, []int32{8080}, dashboardLabels)
if !util.IsTestMode() {
if !serviceStatus.Continue {
logrus.Info("Waiting on service '" + Dashboard + "' to be ready")
if serviceStatus.Err != nil {
logrus.Error(serviceStatus.Err)
}

return false, serviceStatus.Err
}
}

_, done, err = expose.ExposeWithHost(deployContext, cheHost, dashboardComponent, cheHost, "/dashboard")

return done, err
}
197 changes: 197 additions & 0 deletions pkg/deploy/dashboard/deployment_dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
//
// 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 dashboard

import (
"github.com/eclipse/che-operator/pkg/deploy"
"strconv"
"strings"

orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/eclipse/che-operator/pkg/util"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func SyncDashboardDeploymentToCluster(deployContext *deploy.DeployContext) (bool, error) {
component := getDashboardComponent(deployContext)
clusterDeployment, err := deploy.GetClusterDeployment(component, deployContext.CheCluster.Namespace, deployContext.ClusterAPI.Client)
if err != nil {
return false, err
}

specDeployment, err := getSpecDashboardDeployment(deployContext)
if err != nil {
return false, err
}

return deploy.SyncDeploymentToCluster(deployContext, specDeployment, clusterDeployment, nil, nil)
}

func getDashboardComponent(deployContext *deploy.DeployContext) string {
cheFlavor := deploy.DefaultCheFlavor(deployContext.CheCluster)
return cheFlavor + "-dashboard"
}

func getSpecDashboardDeployment(deployContext *deploy.DeployContext) (*appsv1.Deployment, error) {
isOpenShift, _, err := util.DetectOpenShift()
if err != nil {
return nil, err
}

terminationGracePeriodSeconds := int64(30)
cheFlavor := deploy.DefaultCheFlavor(deployContext.CheCluster)
dashboardComponent := getDashboardComponent(deployContext)
labels := deploy.GetLabels(deployContext.CheCluster, dashboardComponent)
memRequest := util.GetValue(deployContext.CheCluster.Spec.Server.ServerMemoryRequest, deploy.DefaultServerMemoryRequest)

memLimit := util.GetValue(deployContext.CheCluster.Spec.Server.ServerMemoryLimit, deploy.DefaultServerMemoryLimit)
dashboardImageAndTag := "quay.io/eclipse/che-dashboard:next"
pullPolicy := corev1.PullPolicy(util.GetValue(string(deployContext.CheCluster.Spec.Server.CheImagePullPolicy), deploy.DefaultPullPolicyFromDockerImage(dashboardImageAndTag)))

deployment := &appsv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: dashboardComponent,
Namespace: deployContext.CheCluster.Namespace,
Labels: labels,
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{MatchLabels: labels},
Strategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: labels,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: cheFlavor,
ImagePullPolicy: pullPolicy,
Image: dashboardImageAndTag,
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 8080,
Protocol: "TCP",
},
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceMemory: resource.MustParse(memRequest),
},
Limits: corev1.ResourceList{
corev1.ResourceMemory: resource.MustParse(memLimit),
},
},
},
},
RestartPolicy: "Always",
TerminationGracePeriodSeconds: &terminationGracePeriodSeconds,
},
},
},
}

// configure probes if debug isn't set
//deployment.Spec.Template.Spec.Containers[0].ReadinessProbe = &corev1.Probe{
// Handler: corev1.Handler{
// HTTPGet: &corev1.HTTPGetAction{
// Path: "/api/system/state",
// Port: intstr.IntOrString{
// Type: intstr.Int,
// IntVal: int32(8080),
// },
// Scheme: corev1.URISchemeHTTP,
// },
// },
// // After POD start, the POD will be seen as ready after a minimum of 15 seconds and we expect it to be seen as ready until a maximum of 200 seconds
// // 200 s = InitialDelaySeconds + PeriodSeconds * (FailureThreshold - 1) + TimeoutSeconds
// InitialDelaySeconds: 25,
// FailureThreshold: 18,
// TimeoutSeconds: 5,
// PeriodSeconds: 10,
// SuccessThreshold: 1,
//}
//deployment.Spec.Template.Spec.Containers[0].LivenessProbe = &corev1.Probe{
// Handler: corev1.Handler{
// HTTPGet: &corev1.HTTPGetAction{
// Path: "/api/system/state",
// Port: intstr.IntOrString{
// Type: intstr.Int,
// IntVal: int32(8080),
// },
// Scheme: corev1.URISchemeHTTP,
// },
// },
// // After POD start, don't initiate liveness probe while the POD is still expected to be declared as ready by the readiness probe
// InitialDelaySeconds: 200,
// FailureThreshold: 3,
// TimeoutSeconds: 3,
// PeriodSeconds: 10,
// SuccessThreshold: 1,
//}

if !isOpenShift {
runAsUser, err := strconv.ParseInt(util.GetValue(deployContext.CheCluster.Spec.K8s.SecurityContextRunAsUser, deploy.DefaultSecurityContextRunAsUser), 10, 64)
if err != nil {
return nil, err
}
fsGroup, err := strconv.ParseInt(util.GetValue(deployContext.CheCluster.Spec.K8s.SecurityContextFsGroup, deploy.DefaultSecurityContextFsGroup), 10, 64)
if err != nil {
return nil, err
}
deployment.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{
RunAsUser: &runAsUser,
FSGroup: &fsGroup,
}
}

if !util.IsTestMode() {
err = controllerutil.SetControllerReference(deployContext.CheCluster, deployment, deployContext.ClusterAPI.Scheme)
if err != nil {
return nil, err
}
}

return deployment, nil
}

// GetFullCheServerImageLink evaluate full cheImage link(with repo and tag)
// based on Checluster information and image defaults from env variables
func GetFullDashboardServerImageLink(checluster *orgv1.CheCluster) string {
if len(checluster.Spec.Server.CheImage) > 0 {
cheServerImageTag := util.GetValue(checluster.Spec.Server.CheImageTag, deploy.DefaultCheVersion())
return checluster.Spec.Server.CheImage + ":" + cheServerImageTag
}

defaultCheServerImage := deploy.DefaultCheServerImage(checluster)
if len(checluster.Spec.Server.CheImageTag) == 0 {
return defaultCheServerImage
}

// For back compatibility with version < 7.9.0:
// if cr.Spec.Server.CheImage is empty, but cr.Spec.Server.CheImageTag is not empty,
// parse from default Che image(value comes from env variable) "Che image repository"
// and return "Che image", like concatenation: "cheImageRepo:cheImageTag"
separator := map[bool]string{true: "@", false: ":"}[strings.Contains(defaultCheServerImage, "@")]
imageParts := strings.Split(defaultCheServerImage, separator)
return imageParts[0] + ":" + checluster.Spec.Server.CheImageTag
}
Loading

0 comments on commit 063fb6d

Please sign in to comment.