From ab0320b62865c0da86abe4cf695e0a8fc9bcd08a Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Fri, 22 Apr 2022 14:18:16 +0000 Subject: [PATCH 1/8] Add PodConfig under a new Common field Allow a new `common` field under `experimental` for cross-cutting concerns such as replica counts. --- .../installer/pkg/config/v1/experimental/experimental.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/install/installer/pkg/config/v1/experimental/experimental.go b/install/installer/pkg/config/v1/experimental/experimental.go index e70681ebe3881d..a515371804f97a 100644 --- a/install/installer/pkg/config/v1/experimental/experimental.go +++ b/install/installer/pkg/config/v1/experimental/experimental.go @@ -17,6 +17,15 @@ type Config struct { Workspace *WorkspaceConfig `json:"workspace,omitempty"` WebApp *WebAppConfig `json:"webapp,omitempty"` IDE *IDEConfig `json:"ide,omitempty"` + Common *CommonConfig `json:"common,omitempty"` +} + +type CommonConfig struct { + PodConfig map[string]*PodConfig `json:"podConfig,omitempty"` +} + +type PodConfig struct { + Replicas *int32 `json:"replicas,omitempty"` } type WorkspaceConfig struct { From a21ef0a974f78ff75d22a2f58f8a6e39a4a6ec39 Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Fri, 22 Apr 2022 14:19:49 +0000 Subject: [PATCH 2/8] Add common.Replicas function To allow lookup of replica counts. Defaults to one if there is no replica count configured for a component. --- install/installer/pkg/common/common.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/install/installer/pkg/common/common.go b/install/installer/pkg/common/common.go index 83bdeb52fd068a..3b4c4aa07df9c5 100644 --- a/install/installer/pkg/common/common.go +++ b/install/installer/pkg/common/common.go @@ -337,6 +337,20 @@ func NodeAffinity(orLabels ...string) *corev1.Affinity { } } +func Replicas(ctx *RenderContext, component string) *int32 { + replicas := int32(1) + + _ = ctx.WithExperimental(func(cfg *experimental.Config) error { + if cfg.Common != nil && cfg.Common.PodConfig[component] != nil { + if cfg.Common.PodConfig[component].Replicas != nil { + replicas = *cfg.Common.PodConfig[component].Replicas + } + } + return nil + }) + return &replicas +} + // ObjectHash marshals the objects to YAML and produces a sha256 hash of the output. // This function is useful for restarting pods when the config changes. // Takes an error as argument to make calling it more conventient. If that error is not nil, From 5b936ca8bff7cd31b1af06351792b70e8cf6884d Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Fri, 22 Apr 2022 14:28:14 +0000 Subject: [PATCH 3/8] Set Replicas for multiple components So that they respect the new `experimental.common.podConfig..replicas` setting. --- install/installer/pkg/components/blobserve/deployment.go | 2 +- install/installer/pkg/components/content-service/deployment.go | 2 +- install/installer/pkg/components/dashboard/deployment.go | 3 +-- .../installer/pkg/components/database/cloudsql/deployment.go | 3 +-- install/installer/pkg/components/ide-proxy/deployment.go | 3 +-- .../installer/pkg/components/image-builder-mk3/deployment.go | 2 +- install/installer/pkg/components/proxy/deployment.go | 2 +- .../installer/pkg/components/public-api-server/deployment.go | 2 +- install/installer/pkg/components/server/deployment.go | 3 +-- .../installer/pkg/components/ws-manager-bridge/deployment.go | 2 +- install/installer/pkg/components/ws-manager/deployment.go | 2 +- install/installer/pkg/components/ws-proxy/deployment.go | 3 +-- 12 files changed, 12 insertions(+), 17 deletions(-) diff --git a/install/installer/pkg/components/blobserve/deployment.go b/install/installer/pkg/components/blobserve/deployment.go index 11c92d54e7137d..6df96a7617d83b 100644 --- a/install/installer/pkg/components/blobserve/deployment.go +++ b/install/installer/pkg/components/blobserve/deployment.go @@ -60,7 +60,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/content-service/deployment.go b/install/installer/pkg/components/content-service/deployment.go index c7c7cd2c2f62fa..ba30fdd20e15ff 100644 --- a/install/installer/pkg/components/content-service/deployment.go +++ b/install/installer/pkg/components/content-service/deployment.go @@ -96,7 +96,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: v1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/dashboard/deployment.go b/install/installer/pkg/components/dashboard/deployment.go index b4446fa5cb6d16..c68829fee53dc4 100644 --- a/install/installer/pkg/components/dashboard/deployment.go +++ b/install/installer/pkg/components/dashboard/deployment.go @@ -30,8 +30,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - // todo(sje): receive config value - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/database/cloudsql/deployment.go b/install/installer/pkg/components/database/cloudsql/deployment.go index c39057252015ac..12a61f8237cc83 100644 --- a/install/installer/pkg/components/database/cloudsql/deployment.go +++ b/install/installer/pkg/components/database/cloudsql/deployment.go @@ -35,8 +35,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, }, Selector: &metav1.LabelSelector{MatchLabels: labels}, - // todo(sje): receive config value - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: Component, diff --git a/install/installer/pkg/components/ide-proxy/deployment.go b/install/installer/pkg/components/ide-proxy/deployment.go index fb0ecb4e5c4144..609ea147d7ca5c 100644 --- a/install/installer/pkg/components/ide-proxy/deployment.go +++ b/install/installer/pkg/components/ide-proxy/deployment.go @@ -30,8 +30,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - // todo(sje): receive config value - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/image-builder-mk3/deployment.go b/install/installer/pkg/components/image-builder-mk3/deployment.go index 02e28ef445ef99..0bce107b4a9c4e 100644 --- a/install/installer/pkg/components/image-builder-mk3/deployment.go +++ b/install/installer/pkg/components/image-builder-mk3/deployment.go @@ -118,7 +118,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/proxy/deployment.go b/install/installer/pkg/components/proxy/deployment.go index 0287238920cd15..cfa022bb0c2ef5 100644 --- a/install/installer/pkg/components/proxy/deployment.go +++ b/install/installer/pkg/components/proxy/deployment.go @@ -105,7 +105,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/public-api-server/deployment.go b/install/installer/pkg/components/public-api-server/deployment.go index 777f87da5a4ad5..273e1d17cfbb05 100644 --- a/install/installer/pkg/components/public-api-server/deployment.go +++ b/install/installer/pkg/components/public-api-server/deployment.go @@ -27,7 +27,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/server/deployment.go b/install/installer/pkg/components/server/deployment.go index eb1859c0f52622..2d8b69b565b924 100644 --- a/install/installer/pkg/components/server/deployment.go +++ b/install/installer/pkg/components/server/deployment.go @@ -173,8 +173,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - // todo(sje): receive config value - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/ws-manager-bridge/deployment.go b/install/installer/pkg/components/ws-manager-bridge/deployment.go index fc0f075fdd2ad6..cc88e89a73dfd5 100644 --- a/install/installer/pkg/components/ws-manager-bridge/deployment.go +++ b/install/installer/pkg/components/ws-manager-bridge/deployment.go @@ -72,7 +72,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/ws-manager/deployment.go b/install/installer/pkg/components/ws-manager/deployment.go index 613caae33ef9a9..57563ff678a820 100644 --- a/install/installer/pkg/components/ws-manager/deployment.go +++ b/install/installer/pkg/components/ws-manager/deployment.go @@ -133,7 +133,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ diff --git a/install/installer/pkg/components/ws-proxy/deployment.go b/install/installer/pkg/components/ws-proxy/deployment.go index 0cd40fcb8be4d2..aea11d23092ee7 100644 --- a/install/installer/pkg/components/ws-proxy/deployment.go +++ b/install/installer/pkg/components/ws-proxy/deployment.go @@ -70,8 +70,7 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) { }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{MatchLabels: labels}, - // todo(sje): receive config value - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Strategy: common.DeploymentStrategy, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ From c55e327901b1f1ade577dab923edc2a0e188d449 Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Mon, 25 Apr 2022 09:17:16 +0000 Subject: [PATCH 4/8] Make StatefulSet replicas configurable --- install/installer/pkg/components/openvsx-proxy/statefulset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/installer/pkg/components/openvsx-proxy/statefulset.go b/install/installer/pkg/components/openvsx-proxy/statefulset.go index 5d98021d5e582a..3a5ebfcf76a05d 100644 --- a/install/installer/pkg/components/openvsx-proxy/statefulset.go +++ b/install/installer/pkg/components/openvsx-proxy/statefulset.go @@ -41,7 +41,7 @@ func statefulset(ctx *common.RenderContext) ([]runtime.Object, error) { }, ServiceName: Component, // todo(sje): receive config value - Replicas: pointer.Int32(1), + Replicas: common.Replicas(ctx, Component), Template: v1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: Component, From c2cc65e69dd27102e416852a15bb3f4498942b6e Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Mon, 25 Apr 2022 09:49:18 +0000 Subject: [PATCH 5/8] Add test for common.Replicas function --- install/installer/pkg/common/render_test.go | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/install/installer/pkg/common/render_test.go b/install/installer/pkg/common/render_test.go index 2dcf60283d82bb..ad1cfa3f13cb2b 100644 --- a/install/installer/pkg/common/render_test.go +++ b/install/installer/pkg/common/render_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/gitpod-io/gitpod/installer/pkg/config/v1" + "github.com/gitpod-io/gitpod/installer/pkg/config/v1/experimental" "github.com/gitpod-io/gitpod/installer/pkg/config/versions" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" @@ -28,6 +29,46 @@ func TestCompositeRenderFunc_NilObjectsNilError(t *testing.T) { require.Len(t, objects, 0) } +func TestReplicas(t *testing.T) { + testCases := []struct { + Component string + ExpectedReplicas int32 + }{ + { + Component: "server", + ExpectedReplicas: 123, + }, + { + Component: "dashboard", + ExpectedReplicas: 456, + }, + { + Component: "content-service", + ExpectedReplicas: 1, + }, + } + ctx, err := NewRenderContext(config.Config{ + Experimental: &experimental.Config{ + Common: &experimental.CommonConfig{ + PodConfig: map[string]*experimental.PodConfig{ + "server": {Replicas: pointer.Int32(123)}, + "dashboard": {Replicas: pointer.Int32(456)}, + }, + }, + }, + }, versions.Manifest{}, "test_namespace") + require.NoError(t, err) + + for _, testCase := range testCases { + actualReplicas := Replicas(ctx, testCase.Component) + + if *actualReplicas != testCase.ExpectedReplicas { + t.Errorf("expected %d replicas for %q component, but got %d", + testCase.ExpectedReplicas, testCase.Component, *actualReplicas) + } + } +} + func TestRepoName(t *testing.T) { type Expectation struct { Result string From 672ff2e83ca971af03856cceacab94c9f15082ce Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Mon, 25 Apr 2022 11:47:58 +0000 Subject: [PATCH 6/8] Use constants for component names --- install/installer/pkg/common/render_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/install/installer/pkg/common/render_test.go b/install/installer/pkg/common/render_test.go index ad1cfa3f13cb2b..65d0fc026e0fce 100644 --- a/install/installer/pkg/common/render_test.go +++ b/install/installer/pkg/common/render_test.go @@ -6,6 +6,9 @@ package common import ( "testing" + "github.com/gitpod-io/gitpod/installer/pkg/components/content_service" + "github.com/gitpod-io/gitpod/installer/pkg/components/dashboard" + "github.com/gitpod-io/gitpod/installer/pkg/components/server" "github.com/gitpod-io/gitpod/installer/pkg/config/v1" "github.com/gitpod-io/gitpod/installer/pkg/config/v1/experimental" "github.com/gitpod-io/gitpod/installer/pkg/config/versions" @@ -35,15 +38,15 @@ func TestReplicas(t *testing.T) { ExpectedReplicas int32 }{ { - Component: "server", + Component: server.Component, ExpectedReplicas: 123, }, { - Component: "dashboard", + Component: dashboard.Component, ExpectedReplicas: 456, }, { - Component: "content-service", + Component: content_service.Component, ExpectedReplicas: 1, }, } From 725fbd066463194c98b6f9981e112768185d36cc Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Mon, 25 Apr 2022 15:30:12 +0000 Subject: [PATCH 7/8] Move tests to common_test package To avoid problems with import cycles when importing components/* packages. --- install/installer/pkg/common/render_test.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/install/installer/pkg/common/render_test.go b/install/installer/pkg/common/render_test.go index 65d0fc026e0fce..a35f2e2e0b8335 100644 --- a/install/installer/pkg/common/render_test.go +++ b/install/installer/pkg/common/render_test.go @@ -1,12 +1,13 @@ // Copyright (c) 2022 Gitpod GmbH. All rights reserved. // Licensed under the MIT License. See License-MIT.txt in the project root for license information. -package common +package common_test import ( "testing" - "github.com/gitpod-io/gitpod/installer/pkg/components/content_service" + "github.com/gitpod-io/gitpod/installer/pkg/common" + content_service "github.com/gitpod-io/gitpod/installer/pkg/components/content-service" "github.com/gitpod-io/gitpod/installer/pkg/components/dashboard" "github.com/gitpod-io/gitpod/installer/pkg/components/server" "github.com/gitpod-io/gitpod/installer/pkg/config/v1" @@ -19,12 +20,12 @@ import ( ) func TestCompositeRenderFunc_NilObjectsNilError(t *testing.T) { - f := CompositeRenderFunc( - func(cfg *RenderContext) ([]runtime.Object, error) { + f := common.CompositeRenderFunc( + func(cfg *common.RenderContext) ([]runtime.Object, error) { return nil, nil }) - ctx, err := NewRenderContext(config.Config{}, versions.Manifest{}, "test_namespace") + ctx, err := common.NewRenderContext(config.Config{}, versions.Manifest{}, "test_namespace") require.NoError(t, err) objects, err := f(ctx) @@ -50,7 +51,7 @@ func TestReplicas(t *testing.T) { ExpectedReplicas: 1, }, } - ctx, err := NewRenderContext(config.Config{ + ctx, err := common.NewRenderContext(config.Config{ Experimental: &experimental.Config{ Common: &experimental.CommonConfig{ PodConfig: map[string]*experimental.PodConfig{ @@ -63,7 +64,7 @@ func TestReplicas(t *testing.T) { require.NoError(t, err) for _, testCase := range testCases { - actualReplicas := Replicas(ctx, testCase.Component) + actualReplicas := common.Replicas(ctx, testCase.Component) if *actualReplicas != testCase.ExpectedReplicas { t.Errorf("expected %d replicas for %q component, but got %d", @@ -170,7 +171,7 @@ func TestRepoName(t *testing.T) { } }() - ctx, err := NewRenderContext(config.Config{ + ctx, err := common.NewRenderContext(config.Config{ DropImageRepo: test.DropImageRepo, Repository: test.CfgRepo, }, versions.Manifest{}, "test_namespace") From dedf7d3d53e366f93e01a0c804450bab96d8ee19 Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Mon, 25 Apr 2022 16:31:32 +0000 Subject: [PATCH 8/8] Give each test a name and use t.Run To run each testcase as a sub-test. --- install/installer/pkg/common/render_test.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/install/installer/pkg/common/render_test.go b/install/installer/pkg/common/render_test.go index a35f2e2e0b8335..700d56b41c178d 100644 --- a/install/installer/pkg/common/render_test.go +++ b/install/installer/pkg/common/render_test.go @@ -36,18 +36,22 @@ func TestCompositeRenderFunc_NilObjectsNilError(t *testing.T) { func TestReplicas(t *testing.T) { testCases := []struct { Component string + Name string ExpectedReplicas int32 }{ { Component: server.Component, + Name: "server takes replica count from common config", ExpectedReplicas: 123, }, { Component: dashboard.Component, + Name: "dashboard takes replica count from common config", ExpectedReplicas: 456, }, { Component: content_service.Component, + Name: "content_service takes default replica count", ExpectedReplicas: 1, }, } @@ -64,12 +68,14 @@ func TestReplicas(t *testing.T) { require.NoError(t, err) for _, testCase := range testCases { - actualReplicas := common.Replicas(ctx, testCase.Component) + t.Run(testCase.Name, func(t *testing.T) { + actualReplicas := common.Replicas(ctx, testCase.Component) - if *actualReplicas != testCase.ExpectedReplicas { - t.Errorf("expected %d replicas for %q component, but got %d", - testCase.ExpectedReplicas, testCase.Component, *actualReplicas) - } + if *actualReplicas != testCase.ExpectedReplicas { + t.Errorf("expected %d replicas for %q component, but got %d", + testCase.ExpectedReplicas, testCase.Component, *actualReplicas) + } + }) } }