// Copyright (c) 2021 Gitpod GmbH. All rights reserved. // Licensed under the GNU Affero General Public License (AGPL). // See License.AGPL.txt in the project root for license information. package openvsx_proxy import ( "fmt" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/pointer" "github.com/gitpod-io/gitpod/common-go/baseserver" "github.com/gitpod-io/gitpod/installer/pkg/cluster" "github.com/gitpod-io/gitpod/installer/pkg/common" ) func statefulset(ctx *common.RenderContext) ([]runtime.Object, error) { labels := common.CustomizeLabel(ctx, Component, common.TypeMetaStatefulSet) // todo(sje): add redis configHash, err := common.ObjectHash(configmap(ctx)) if err != nil { return nil, err } volumeClaimTemplates := []v1.PersistentVolumeClaim{ { ObjectMeta: metav1.ObjectMeta{ Name: "redis-data", Labels: common.DefaultLabels(Component), }, Spec: v1.PersistentVolumeClaimSpec{ AccessModes: []v1.PersistentVolumeAccessMode{ v1.ReadWriteOnce, }, Resources: v1.ResourceRequirements{ Requests: v1.ResourceList{ "storage": resource.MustParse("8Gi"), }, }, }, }, } volumes := []v1.Volume{ { Name: "config", VolumeSource: v1.VolumeSource{ ConfigMap: &v1.ConfigMapVolumeSource{ LocalObjectReference: v1.LocalObjectReference{Name: fmt.Sprintf("%s-config", Component)}, }, }, }, } if ctx.Config.OpenVSX.Proxy != nil && ctx.Config.OpenVSX.Proxy.DisablePVC { volumeClaimTemplates = nil volumes = append(volumes, *common.NewEmptyDirVolume("redis-data")) } const redisContainerName = "redis" return []runtime.Object{&appsv1.StatefulSet{ TypeMeta: common.TypeMetaStatefulSet, ObjectMeta: metav1.ObjectMeta{ Name: Component, Namespace: ctx.Namespace, Labels: labels, Annotations: common.CustomizeAnnotation(ctx, Component, common.TypeMetaConfigmap), }, Spec: appsv1.StatefulSetSpec{ Selector: &metav1.LabelSelector{ MatchLabels: common.DefaultLabels(Component), }, ServiceName: Component, // todo(sje): receive config value Replicas: common.Replicas(ctx, Component), Template: v1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: Component, Namespace: ctx.Namespace, Labels: labels, Annotations: common.CustomizeAnnotation(ctx, Component, common.TypeMetaConfigmap, func() map[string]string { return map[string]string{ common.AnnotationConfigChecksum: configHash, } }), }, Spec: v1.PodSpec{ Affinity: common.NodeAffinity(cluster.AffinityLabelIDE), ServiceAccountName: Component, EnableServiceLinks: pointer.Bool(false), DNSPolicy: "ClusterFirst", RestartPolicy: "Always", TerminationGracePeriodSeconds: pointer.Int64(30), Volumes: volumes, Containers: []v1.Container{{ Name: Component, Image: ctx.ImageName(ctx.Config.Repository, Component, ctx.VersionManifest.Components.OpenVSXProxy.Version), Args: []string{"/config/config.json"}, ReadinessProbe: &v1.Probe{ ProbeHandler: v1.ProbeHandler{ HTTPGet: &v1.HTTPGetAction{ Path: "/openvsx-proxy-status", Port: intstr.IntOrString{IntVal: ContainerPort}, }, }, }, SecurityContext: &v1.SecurityContext{ AllowPrivilegeEscalation: pointer.Bool(false), }, ImagePullPolicy: v1.PullIfNotPresent, Resources: common.ResourceRequirements(ctx, Component, Component, v1.ResourceRequirements{ Requests: v1.ResourceList{ "cpu": resource.MustParse("1m"), "memory": resource.MustParse("150Mi"), }, }), Ports: []v1.ContainerPort{{ Name: PortName, ContainerPort: ContainerPort, }, { Name: baseserver.BuiltinMetricsPortName, ContainerPort: baseserver.BuiltinMetricsPort, }}, VolumeMounts: []v1.VolumeMount{{ Name: "config", MountPath: "/config", }}, Env: common.CustomizeEnvvar(ctx, Component, common.MergeEnv( common.DefaultEnv(&ctx.Config), common.ConfigcatEnv(ctx), )), }, { Name: redisContainerName, Image: ctx.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, common.DockerRegistryURL), "library/redis", "6.2"), Command: []string{ "redis-server", "/config/redis.conf", }, Env: []v1.EnvVar{{ Name: "MASTER", Value: "true", }}, ImagePullPolicy: "IfNotPresent", Ports: []v1.ContainerPort{{ ContainerPort: 6379, }}, SecurityContext: &v1.SecurityContext{ AllowPrivilegeEscalation: pointer.Bool(false), }, Resources: common.ResourceRequirements(ctx, Component, redisContainerName, v1.ResourceRequirements{ Requests: v1.ResourceList{ "cpu": resource.MustParse("1m"), "memory": resource.MustParse("150Mi"), }, }), VolumeMounts: []v1.VolumeMount{{ Name: "config", MountPath: "/config", }, { Name: "redis-data", MountPath: "/data", }}, }, *common.KubeRBACProxyContainer(ctx), }, }, }, VolumeClaimTemplates: volumeClaimTemplates, }}, }, nil }