Skip to content

Commit

Permalink
restart/stop oauth2 service on component stop/restart (#980)
Browse files Browse the repository at this point in the history
  • Loading branch information
nilsgstrabo authored Nov 17, 2023
1 parent 8b18753 commit ac4747f
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 41 deletions.
4 changes: 2 additions & 2 deletions charts/radix-operator/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v2
name: radix-operator
version: 1.25.3
appVersion: 1.45.3
version: 1.25.4
appVersion: 1.45.4
kubeVersion: ">=1.24.0"
description: Radix Operator
keywords:
Expand Down
8 changes: 2 additions & 6 deletions pkg/apis/deployment/kubedeployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (deploy *Deployment) getDesiredCreatedDeploymentConfig(deployComponent v1.R
desiredDeployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{Labels: make(map[string]string), Annotations: make(map[string]string)},
Spec: appsv1.DeploymentSpec{
Replicas: int32Ptr(DefaultReplicas),
Replicas: pointers.Ptr[int32](DefaultReplicas),
Selector: &metav1.LabelSelector{MatchLabels: make(map[string]string)},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: make(map[string]string), Annotations: make(map[string]string)},
Expand All @@ -122,7 +122,7 @@ func (deploy *Deployment) createJobAuxDeployment(deployComponent v1.RadixCommonD
Annotations: make(map[string]string),
},
Spec: appsv1.DeploymentSpec{
Replicas: int32Ptr(1),
Replicas: pointers.Ptr[int32](1),
Selector: &metav1.LabelSelector{MatchLabels: radixlabels.ForJobAuxObject(jobName)},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: make(map[string]string), Annotations: make(map[string]string)},
Expand Down Expand Up @@ -474,7 +474,3 @@ func getContainerPorts(deployComponent v1.RadixCommonDeployComponent) []corev1.C
}
return ports
}

func int32Ptr(i int32) *int32 {
return &i
}
15 changes: 13 additions & 2 deletions pkg/apis/deployment/oauthproxyresourcemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

commonutils "github.com/equinor/radix-common/utils"
radixmaps "github.com/equinor/radix-common/utils/maps"
"github.com/equinor/radix-common/utils/pointers"
"github.com/equinor/radix-operator/pkg/apis/defaults"
"github.com/equinor/radix-operator/pkg/apis/kube"
v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
Expand Down Expand Up @@ -669,6 +670,11 @@ func (o *oauthProxyResourceManager) getDesiredDeployment(component v1.RadixCommo
return nil, err
}

var replicas int32 = 1
if isComponentStopped(component) {
replicas = 0
}

// Spec.Strategy defaults to RollingUpdate, ref https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy
desiredDeployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -677,7 +683,7 @@ func (o *oauthProxyResourceManager) getDesiredDeployment(component v1.RadixCommo
OwnerReferences: []metav1.OwnerReference{getOwnerReferenceOfDeployment(o.rd)},
},
Spec: appsv1.DeploymentSpec{
Replicas: int32Ptr(DefaultReplicas),
Replicas: pointers.Ptr(replicas),
Selector: &metav1.LabelSelector{
MatchLabels: o.getLabelsForAuxComponent(component),
},
Expand Down Expand Up @@ -728,7 +734,12 @@ func (o *oauthProxyResourceManager) getEnvVars(component v1.RadixCommonDeployCom
}
}

// Add fixed envvars
// Radix envvars
if v, ok := component.GetEnvironmentVariables()[defaults.RadixRestartEnvironmentVariable]; ok {
envVars = append(envVars, corev1.EnvVar{Name: defaults.RadixRestartEnvironmentVariable, Value: v})
}

// oauth2-proxy envvars
envVars = append(envVars, corev1.EnvVar{Name: "OAUTH2_PROXY_PROVIDER", Value: "oidc"})
envVars = append(envVars, corev1.EnvVar{Name: "OAUTH2_PROXY_COOKIE_HTTPONLY", Value: "true"})
envVars = append(envVars, corev1.EnvVar{Name: "OAUTH2_PROXY_COOKIE_SECURE", Value: "true"})
Expand Down
165 changes: 138 additions & 27 deletions pkg/apis/deployment/oauthproxyresourcemanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package deployment
import (
"context"
"fmt"
"os"
"reflect"
"testing"

commonUtils "github.com/equinor/radix-common/utils"
"github.com/equinor/radix-common/utils/pointers"
"github.com/equinor/radix-common/utils/slice"
"github.com/equinor/radix-operator/pkg/apis/defaults"
"github.com/equinor/radix-operator/pkg/apis/defaults/k8s"
"github.com/equinor/radix-operator/pkg/apis/kube"
Expand Down Expand Up @@ -47,32 +48,18 @@ func TestOAuthProxyResourceManagerTestSuite(t *testing.T) {
suite.Run(t, new(OAuthProxyResourceManagerTestSuite))
}

func (*OAuthProxyResourceManagerTestSuite) SetupSuite() {
os.Setenv(defaults.OperatorDefaultUserGroupEnvironmentVariable, "1234-5678-91011")
os.Setenv(defaults.OperatorDNSZoneEnvironmentVariable, dnsZone)
os.Setenv(defaults.OperatorAppAliasBaseURLEnvironmentVariable, "app.dev.radix.equinor.com")
os.Setenv(defaults.OperatorEnvLimitDefaultMemoryEnvironmentVariable, "300M")
os.Setenv(defaults.OperatorRollingUpdateMaxUnavailable, "25%")
os.Setenv(defaults.OperatorRollingUpdateMaxSurge, "25%")
os.Setenv(defaults.OperatorReadinessProbeInitialDelaySeconds, "5")
os.Setenv(defaults.OperatorReadinessProbePeriodSeconds, "10")
os.Setenv(defaults.OperatorRadixJobSchedulerEnvironmentVariable, "radix-job-scheduler:main-latest")
os.Setenv(defaults.OperatorClusterTypeEnvironmentVariable, "development")
os.Setenv(defaults.RadixOAuthProxyDefaultOIDCIssuerURLEnvironmentVariable, "oidc_issuer_url")
}

func (*OAuthProxyResourceManagerTestSuite) TearDownSuite() {
os.Unsetenv(defaults.OperatorDefaultUserGroupEnvironmentVariable)
os.Unsetenv(defaults.OperatorDNSZoneEnvironmentVariable)
os.Unsetenv(defaults.OperatorAppAliasBaseURLEnvironmentVariable)
os.Unsetenv(defaults.OperatorEnvLimitDefaultMemoryEnvironmentVariable)
os.Unsetenv(defaults.OperatorRollingUpdateMaxUnavailable)
os.Unsetenv(defaults.OperatorRollingUpdateMaxSurge)
os.Unsetenv(defaults.OperatorReadinessProbeInitialDelaySeconds)
os.Unsetenv(defaults.OperatorReadinessProbePeriodSeconds)
os.Unsetenv(defaults.OperatorRadixJobSchedulerEnvironmentVariable)
os.Unsetenv(defaults.OperatorClusterTypeEnvironmentVariable)
os.Unsetenv(defaults.RadixOAuthProxyDefaultOIDCIssuerURLEnvironmentVariable)
func (s *OAuthProxyResourceManagerTestSuite) SetupSuite() {
s.T().Setenv(defaults.OperatorDefaultUserGroupEnvironmentVariable, "1234-5678-91011")
s.T().Setenv(defaults.OperatorDNSZoneEnvironmentVariable, dnsZone)
s.T().Setenv(defaults.OperatorAppAliasBaseURLEnvironmentVariable, "app.dev.radix.equinor.com")
s.T().Setenv(defaults.OperatorEnvLimitDefaultMemoryEnvironmentVariable, "300M")
s.T().Setenv(defaults.OperatorRollingUpdateMaxUnavailable, "25%")
s.T().Setenv(defaults.OperatorRollingUpdateMaxSurge, "25%")
s.T().Setenv(defaults.OperatorReadinessProbeInitialDelaySeconds, "5")
s.T().Setenv(defaults.OperatorReadinessProbePeriodSeconds, "10")
s.T().Setenv(defaults.OperatorRadixJobSchedulerEnvironmentVariable, "radix-job-scheduler:main-latest")
s.T().Setenv(defaults.OperatorClusterTypeEnvironmentVariable, "development")
s.T().Setenv(defaults.RadixOAuthProxyDefaultOIDCIssuerURLEnvironmentVariable, "oidc_issuer_url")
}

func (s *OAuthProxyResourceManagerTestSuite) SetupTest() {
Expand Down Expand Up @@ -108,6 +95,47 @@ func (s *OAuthProxyResourceManagerTestSuite) TestNewOAuthProxyResourceManager()
s.Equal("proxy:123", sut.oauth2ProxyDockerImage)
}

func (s *OAuthProxyResourceManagerTestSuite) Test_Sync_ComponentRestartEnvVar() {
auth := &v1.Authentication{OAuth2: &v1.OAuth2{ClientID: "1234"}}
appName := "anyapp"
rr := utils.NewRegistrationBuilder().WithName(appName).BuildRR()
baseComp := func() utils.DeployComponentBuilder {
return utils.NewDeployComponentBuilder().WithName("comp").WithPublicPort("http").WithAuthentication(auth)
}
type testSpec struct {
name string
rd *v1.RadixDeployment
expectRestartEnvVar bool
}
tests := []testSpec{
{
name: "component default config",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithEnvironmentVariable(defaults.RadixRestartEnvironmentVariable, "anyval")).
BuildRD(),
expectRestartEnvVar: true,
},
{
name: "component replicas set to 1",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithReplicas(pointers.Ptr(1))).
BuildRD(),
expectRestartEnvVar: false,
},
}
s.oauth2Config.EXPECT().MergeWith(gomock.Any()).AnyTimes().Return(&v1.OAuth2{}, nil)
for _, test := range tests {
s.Run(test.name, func() {
sut := &oauthProxyResourceManager{test.rd, rr, s.kubeUtil, []IngressAnnotationProvider{}, s.oauth2Config, ""}
err := sut.Sync()
s.Nil(err)
deploys, _ := s.kubeClient.AppsV1().Deployments(corev1.NamespaceAll).List(context.Background(), metav1.ListOptions{LabelSelector: s.getAppNameSelector(appName)})
envVarExist := slice.Any(deploys.Items[0].Spec.Template.Spec.Containers[0].Env, func(ev corev1.EnvVar) bool { return ev.Name == defaults.RadixRestartEnvironmentVariable })
s.Equal(test.expectRestartEnvVar, envVarExist)
})
}
}

func (s *OAuthProxyResourceManagerTestSuite) Test_Sync_NotPublicOrNoOAuth() {
type scenarioDef struct{ rd *v1.RadixDeployment }
scenarios := []scenarioDef{
Expand Down Expand Up @@ -136,6 +164,89 @@ func (s *OAuthProxyResourceManagerTestSuite) Test_Sync_NotPublicOrNoOAuth() {
}
}

func (s *OAuthProxyResourceManagerTestSuite) Test_Sync_OauthDeploymentReplicas() {
auth := &v1.Authentication{OAuth2: &v1.OAuth2{ClientID: "1234"}}
appName := "anyapp"
rr := utils.NewRegistrationBuilder().WithName(appName).BuildRR()
baseComp := func() utils.DeployComponentBuilder {
return utils.NewDeployComponentBuilder().WithName("comp").WithPublicPort("http").WithAuthentication(auth)
}
type testSpec struct {
name string
rd *v1.RadixDeployment
expectedReplicas int32
}
tests := []testSpec{
{
name: "component default config",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp()).
BuildRD(),
expectedReplicas: 1,
},
{
name: "component replicas set to 1",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithReplicas(pointers.Ptr(1))).
BuildRD(),
expectedReplicas: 1,
},
{
name: "component replicas set to 2",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithReplicas(pointers.Ptr(2))).
BuildRD(),
expectedReplicas: 1,
},
{
name: "component replicas set to 0",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithReplicas(pointers.Ptr(0))).
BuildRD(),
expectedReplicas: 0,
},
{
name: "component with hpa and default config",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithHorizontalScaling(pointers.Ptr[int32](3), 4, pointers.Ptr[int32](1), pointers.Ptr[int32](1))).
BuildRD(),
expectedReplicas: 1,
},
{
name: "component with hpa and replicas set to 1",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithReplicas(pointers.Ptr(1)).WithHorizontalScaling(pointers.Ptr[int32](3), 4, pointers.Ptr[int32](1), pointers.Ptr[int32](1))).
BuildRD(),
expectedReplicas: 1,
},
{
name: "component with hpa and replicas set to 2",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithReplicas(pointers.Ptr(2)).WithHorizontalScaling(pointers.Ptr[int32](3), 4, pointers.Ptr[int32](1), pointers.Ptr[int32](1))).
BuildRD(),
expectedReplicas: 1,
},
{

name: "component with hpa and replicas set to 0",
rd: utils.NewDeploymentBuilder().WithAppName(appName).WithEnvironment("qa").
WithComponent(baseComp().WithReplicas(pointers.Ptr(0)).WithHorizontalScaling(pointers.Ptr[int32](3), 4, pointers.Ptr[int32](1), pointers.Ptr[int32](1))).
BuildRD(),
expectedReplicas: 0,
},
}
s.oauth2Config.EXPECT().MergeWith(gomock.Any()).AnyTimes().Return(&v1.OAuth2{}, nil)
for _, test := range tests {
s.Run(test.name, func() {
sut := &oauthProxyResourceManager{test.rd, rr, s.kubeUtil, []IngressAnnotationProvider{}, s.oauth2Config, ""}
err := sut.Sync()
s.Nil(err)
deploys, _ := s.kubeClient.AppsV1().Deployments(corev1.NamespaceAll).List(context.Background(), metav1.ListOptions{LabelSelector: s.getAppNameSelector(appName)})
s.Equal(test.expectedReplicas, *deploys.Items[0].Spec.Replicas)
})
}
}

func (s *OAuthProxyResourceManagerTestSuite) Test_Sync_OAuthProxyDeploymentCreated() {
appName, envName, componentName := "anyapp", "qa", "server"
envNs := utils.GetEnvironmentNamespace(appName, envName)
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/deployment/pdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package deployment
import (
"context"
"fmt"

"github.com/equinor/radix-common/utils/errors"
"github.com/equinor/radix-operator/pkg/apis/kube"
v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
Expand Down
6 changes: 3 additions & 3 deletions pkg/apis/deployment/radixjobcomponent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func Test_GetRadixJobComponents_BuildAllJobComponents(t *testing.T) {
WithJobComponents(
utils.AnApplicationJobComponent().
WithName("job1").
WithSchedulerPort(int32Ptr(8888)).
WithSchedulerPort(pointers.Ptr[int32](8888)).
WithPayloadPath(utils.StringPtr("/path/to/payload")),
utils.AnApplicationJobComponent().
WithName("job2"),
Expand All @@ -37,7 +37,7 @@ func Test_GetRadixJobComponents_BuildAllJobComponents(t *testing.T) {
require.NoError(t, err)
assert.Len(t, jobs, 2)
assert.Equal(t, "job1", jobs[0].Name)
assert.Equal(t, int32Ptr(8888), jobs[0].SchedulerPort)
assert.Equal(t, pointers.Ptr[int32](8888), jobs[0].SchedulerPort)
assert.Equal(t, "/path/to/payload", jobs[0].Payload.Path)
assert.Equal(t, "job2", jobs[1].Name)
assert.Nil(t, jobs[1].SchedulerPort)
Expand All @@ -51,7 +51,7 @@ func Test_GetRadixJobComponentsWithNode_BuildAllJobComponents(t *testing.T) {
WithJobComponents(
utils.AnApplicationJobComponent().
WithName("job1").
WithSchedulerPort(int32Ptr(8888)).
WithSchedulerPort(pointers.Ptr[int32](8888)).
WithPayloadPath(utils.StringPtr("/path/to/payload")).
WithNode(v1.RadixNode{Gpu: gpu, GpuCount: gpuCount}),
utils.AnApplicationJobComponent().
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/deployment/volumemount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1526,7 +1526,7 @@ func getDesiredDeployment(componentName string, volumes []corev1.Volume) *appsv1
Annotations: make(map[string]string),
},
Spec: appsv1.DeploymentSpec{
Replicas: int32Ptr(DefaultReplicas),
Replicas: pointers.Ptr[int32](DefaultReplicas),
Selector: &metav1.LabelSelector{MatchLabels: make(map[string]string)},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: make(map[string]string), Annotations: make(map[string]string)},
Expand Down

0 comments on commit ac4747f

Please sign in to comment.