From a5bdceeac2edd2ea273b21ccbce09d72826ec9f8 Mon Sep 17 00:00:00 2001 From: Claudio Netto Date: Fri, 5 Aug 2022 14:42:51 -0300 Subject: [PATCH] feat(web): support custom replicas value on instance creation --- internal/config/config.go | 2 + internal/config/config_test.go | 157 +++++++++++++-------------------- internal/pkg/rpaas/k8s.go | 7 +- internal/pkg/rpaas/k8s_test.go | 52 ++++++++++- 4 files changed, 120 insertions(+), 98 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 94bbf8e35..ecfdd1e51 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -52,6 +52,7 @@ type RpaasConfig struct { MultiCluster bool `json:"multi-cluster"` NamespacedInstances bool `json:"namespaced-instances"` EnableCertManager bool `json:"enable-cert-manager"` + NewInstanceReplicas int `json:"new-instance-replicas"` } type ClusterConfig struct { @@ -107,6 +108,7 @@ func Init() error { viper.SetDefault("websocket-max-idle-time", 60*time.Second) viper.SetDefault("websocket-write-wait", time.Second) viper.SetDefault("enable-cert-manager", false) + viper.SetDefault("new-instance-replicas", 1) viper.AutomaticEnv() err := readConfig() if err != nil { diff --git a/internal/config/config_test.go b/internal/config/config_test.go index edaadc317..942eaf129 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -22,33 +22,25 @@ func Test_Init(t *testing.T) { tests := []struct { config string envs map[string]string - expected RpaasConfig + expected func(c RpaasConfig) RpaasConfig }{ + {}, { - expected: RpaasConfig{ - ServiceName: "rpaasv2", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: 1 * time.Minute, - WebSocketWriteWait: time.Second, + config: ` +new-instance-replicas: 5 +`, + expected: func(c RpaasConfig) RpaasConfig { + c.NewInstanceReplicas = 5 + return c }, }, { config: ` sync-interval: 2m `, - expected: RpaasConfig{ - ServiceName: "rpaasv2", - SyncInterval: 2 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: time.Minute, - WebSocketWriteWait: time.Second, + expected: func(c RpaasConfig) RpaasConfig { + c.SyncInterval = 2 * time.Minute + return c }, }, { @@ -56,33 +48,19 @@ sync-interval: 2m tls-certificate: /var/share/tls/mycert.pem tls-key: /var/share/tls/key.pem `, - expected: RpaasConfig{ - ServiceName: "rpaasv2", - TLSCertificate: "/var/share/tls/mycert.pem", - TLSKey: "/var/share/tls/key.pem", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: time.Minute, - WebSocketWriteWait: time.Second, + expected: func(c RpaasConfig) RpaasConfig { + c.TLSCertificate = "/var/share/tls/mycert.pem" + c.TLSKey = "/var/share/tls/key.pem" + return c }, }, { config: ` api-username: u1 `, - expected: RpaasConfig{ - APIUsername: "u1", - ServiceName: "rpaasv2", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: time.Minute, - WebSocketWriteWait: time.Second, + expected: func(c RpaasConfig) RpaasConfig { + c.APIUsername = "u1" + return c }, }, { @@ -94,17 +72,11 @@ service-name: rpaasv2be "RPAASV2_API_USERNAME": "u1", "RPAASV2_API_PASSWORD": "p1", }, - expected: RpaasConfig{ - APIUsername: "u1", - APIPassword: "p1", - ServiceName: "rpaasv2be", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: time.Minute, - WebSocketWriteWait: time.Second, + expected: func(c RpaasConfig) RpaasConfig { + c.APIUsername = "u1" + c.APIPassword = "p1" + c.ServiceName = "rpaasv2be" + return c }, }, { @@ -114,15 +86,9 @@ service-name: ignored-service-name envs: map[string]string{ "RPAASV2_SERVICE_NAME": "my-custom-service-name", }, - expected: RpaasConfig{ - ServiceName: "my-custom-service-name", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: time.Minute, - WebSocketWriteWait: time.Second, + expected: func(c RpaasConfig) RpaasConfig { + c.ServiceName = "my-custom-service-name" + return c }, }, { @@ -147,16 +113,8 @@ team-affinity: values: - dev `, - expected: RpaasConfig{ - ServiceName: "rpaasv2", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: time.Minute, - WebSocketWriteWait: time.Second, - DefaultAffinity: &corev1.Affinity{ + expected: func(c RpaasConfig) RpaasConfig { + c.DefaultAffinity = &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ NodeSelectorTerms: []corev1.NodeSelectorTerm{ @@ -172,8 +130,8 @@ team-affinity: }, }, }, - }, - TeamAffinity: map[string]corev1.Affinity{ + } + c.TeamAffinity = map[string]corev1.Affinity{ "team1": { NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ @@ -191,23 +149,17 @@ team-affinity: }, }, }, - }, + } + return c }, }, { config: ` loadbalancer-name-label-key: my.cloudprovider.example.com/lb-name `, - expected: RpaasConfig{ - ServiceName: "rpaasv2", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: 5 * time.Second, - WebSocketReadBufferSize: 1024, - WebSocketWriteBufferSize: 4096, - WebSocketPingInterval: 2 * time.Second, - WebSocketMaxIdleTime: time.Minute, - WebSocketWriteWait: time.Second, - LoadBalancerNameLabelKey: "my.cloudprovider.example.com/lb-name", + expected: func(c RpaasConfig) RpaasConfig { + c.LoadBalancerNameLabelKey = "my.cloudprovider.example.com/lb-name" + return c }, }, { @@ -225,20 +177,19 @@ config-deny-patterns: - pattern1.* - pattern2.* `, - expected: RpaasConfig{ - ServiceName: "rpaasv2", - SyncInterval: 5 * time.Minute, - WebSocketHandshakeTimeout: time.Minute, - WebSocketReadBufferSize: 8192, - WebSocketWriteBufferSize: 8192, - WebSocketPingInterval: 500 * time.Millisecond, - WebSocketMaxIdleTime: 5 * time.Second, - WebSocketWriteWait: 5 * time.Second, - WebSocketAllowedOrigins: []string{"rpaasv2.example.com", "rpaasv2.test"}, - ConfigDenyPatterns: []regexp.Regexp{ + expected: func(c RpaasConfig) RpaasConfig { + c.WebSocketHandshakeTimeout = time.Minute + c.WebSocketReadBufferSize = 8192 + c.WebSocketWriteBufferSize = 8192 + c.WebSocketPingInterval = 500 * time.Millisecond + c.WebSocketMaxIdleTime = 5 * time.Second + c.WebSocketWriteWait = 5 * time.Second + c.WebSocketAllowedOrigins = []string{"rpaasv2.example.com", "rpaasv2.test"} + c.ConfigDenyPatterns = []regexp.Regexp{ *regexp.MustCompile(`pattern1.*`), *regexp.MustCompile(`pattern2.*`), - }, + } + return c }, }, } @@ -260,7 +211,21 @@ config-deny-patterns: err = Init() require.NoError(t, err) config := Get() - assert.Equal(t, tt.expected, config) + expected := RpaasConfig{ + ServiceName: "rpaasv2", + SyncInterval: 5 * time.Minute, + WebSocketHandshakeTimeout: 5 * time.Second, + WebSocketReadBufferSize: 1024, + WebSocketWriteBufferSize: 4096, + WebSocketPingInterval: 2 * time.Second, + WebSocketMaxIdleTime: 1 * time.Minute, + WebSocketWriteWait: time.Second, + NewInstanceReplicas: 1, + } + if tt.expected != nil { + expected = tt.expected(expected) + } + assert.Equal(t, expected, config) }) } } diff --git a/internal/pkg/rpaas/k8s.go b/internal/pkg/rpaas/k8s.go index 2ea712624..26a3a621a 100644 --- a/internal/pkg/rpaas/k8s.go +++ b/internal/pkg/rpaas/k8s.go @@ -237,10 +237,15 @@ func (m *k8sRpaasManager) CreateInstance(ctx context.Context, args CreateArgs) e return err } + replicas := func(n int32) *int32 { return &n }(1) + if r := config.Get().NewInstanceReplicas; r > 0 { + replicas = func(n int32) *int32 { return &n }(int32(r)) + } + instance := newRpaasInstance(args.Name) instance.Namespace = nsName instance.Spec = v1alpha1.RpaasInstanceSpec{ - Replicas: func(n int32) *int32 { return &n }(int32(1)), + Replicas: replicas, PlanName: plan.Name, Flavors: args.Flavors(), Service: &nginxv1alpha1.NginxService{ diff --git a/internal/pkg/rpaas/k8s_test.go b/internal/pkg/rpaas/k8s_test.go index 1e0578802..f55f648b2 100644 --- a/internal/pkg/rpaas/k8s_test.go +++ b/internal/pkg/rpaas/k8s_test.go @@ -2565,7 +2565,6 @@ func Test_k8sRpaasManager_CreateInstance(t *testing.T) { }{ { name: "without name", - args: CreateArgs{}, expectedError: `name is required`, }, { @@ -2652,6 +2651,56 @@ func Test_k8sRpaasManager_CreateInstance(t *testing.T) { }, }, }, + { + name: "w/ custom number of replicas", + args: CreateArgs{Name: "r1", Team: "t1"}, + extraConfig: config.RpaasConfig{NewInstanceReplicas: 3}, + expected: v1alpha1.RpaasInstance{ + TypeMeta: metav1.TypeMeta{ + Kind: "RpaasInstance", + APIVersion: "extensions.tsuru.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "r1", + Namespace: "rpaasv2", + ResourceVersion: "1", + Annotations: map[string]string{ + "rpaas.extensions.tsuru.io/description": "", + "rpaas.extensions.tsuru.io/tags": "", + "rpaas.extensions.tsuru.io/team-owner": "t1", + }, + Labels: map[string]string{ + "rpaas.extensions.tsuru.io/service-name": "rpaasv2", + "rpaas.extensions.tsuru.io/instance-name": "r1", + "rpaas.extensions.tsuru.io/team-owner": "t1", + "rpaas_service": "rpaasv2", + "rpaas_instance": "r1", + }, + }, + Spec: v1alpha1.RpaasInstanceSpec{ + Replicas: func(n int32) *int32 { return &n }(3), + PlanName: "plan1", + Service: &nginxv1alpha1.NginxService{ + Labels: map[string]string{ + "rpaas.extensions.tsuru.io/service-name": "rpaasv2", + "rpaas.extensions.tsuru.io/instance-name": "r1", + "rpaas.extensions.tsuru.io/team-owner": "t1", + "rpaas_service": "rpaasv2", + "rpaas_instance": "r1", + }, + }, + PodTemplate: nginxv1alpha1.NginxPodTemplateSpec{ + Labels: map[string]string{ + "rpaas.extensions.tsuru.io/service-name": "rpaasv2", + "rpaas.extensions.tsuru.io/instance-name": "r1", + "rpaas.extensions.tsuru.io/team-owner": "t1", + "rpaas_service": "rpaasv2", + "rpaas_instance": "r1", + }, + }, + }, + }, + }, { name: "multi-cluster", args: CreateArgs{Name: "r1", Team: "t1"}, @@ -3051,6 +3100,7 @@ func Test_k8sRpaasManager_CreateInstance(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { baseConfig := config.RpaasConfig{ + NewInstanceReplicas: 1, ServiceName: "rpaasv2", LoadBalancerNameLabelKey: "cloudprovider.example/lb-name", TeamAffinity: map[string]corev1.Affinity{