Unverified Commit 7a5f70f3 authored by Thomas Montfort's avatar Thomas Montfort Committed by GitHub
Browse files

feat(operator): enable maxSurge/maxUnavailable configuration for Deployment...

feat(operator): enable maxSurge/maxUnavailable configuration for Deployment backed components (#4990)
parent fb1b4f92
...@@ -182,7 +182,7 @@ type DynamoComponentDeploymentStatus struct { ...@@ -182,7 +182,7 @@ type DynamoComponentDeploymentStatus struct {
// Service contains replica status information for this service. // Service contains replica status information for this service.
// +optional // +optional
Service ServiceReplicaStatus `json:"service,omitempty"` Service *ServiceReplicaStatus `json:"service,omitempty"`
} }
// +genclient // +genclient
...@@ -223,7 +223,10 @@ func (s *DynamoComponentDeployment) IsReady() (bool, string) { ...@@ -223,7 +223,10 @@ func (s *DynamoComponentDeployment) IsReady() (bool, string) {
} }
func (s *DynamoComponentDeployment) GetServiceStatuses() map[string]ServiceReplicaStatus { func (s *DynamoComponentDeployment) GetServiceStatuses() map[string]ServiceReplicaStatus {
return map[string]ServiceReplicaStatus{s.Spec.ServiceName: s.Status.Service} if s.Status.Service == nil {
return map[string]ServiceReplicaStatus{}
}
return map[string]ServiceReplicaStatus{s.Spec.ServiceName: *s.Status.Service}
} }
func (s *DynamoComponentDeploymentStatus) IsReady() (bool, string) { func (s *DynamoComponentDeploymentStatus) IsReady() (bool, string) {
......
...@@ -421,7 +421,11 @@ func (in *DynamoComponentDeploymentStatus) DeepCopyInto(out *DynamoComponentDepl ...@@ -421,7 +421,11 @@ func (in *DynamoComponentDeploymentStatus) DeepCopyInto(out *DynamoComponentDepl
(*out)[key] = val (*out)[key] = val
} }
} }
in.Service.DeepCopyInto(&out.Service) if in.Service != nil {
in, out := &in.Service, &out.Service
*out = new(ServiceReplicaStatus)
(*in).DeepCopyInto(*out)
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamoComponentDeploymentStatus. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamoComponentDeploymentStatus.
......
...@@ -22,6 +22,4 @@ type DeploymentStrategy string ...@@ -22,6 +22,4 @@ type DeploymentStrategy string
const ( const (
DeploymentStrategyRollingUpdate DeploymentStrategy = "RollingUpdate" DeploymentStrategyRollingUpdate DeploymentStrategy = "RollingUpdate"
DeploymentStrategyRecreate DeploymentStrategy = "Recreate" DeploymentStrategyRecreate DeploymentStrategy = "Recreate"
DeploymentStrategyRampedSlowRollout DeploymentStrategy = "RampedSlowRollout"
DeploymentStrategyBestEffortControlledRollout DeploymentStrategy = "BestEffortControlledRollout"
) )
...@@ -61,6 +61,8 @@ const ( ...@@ -61,6 +61,8 @@ const (
DefaultClusterName = "default" DefaultClusterName = "default"
DefaultServiceAccountName = "default" DefaultServiceAccountName = "default"
KubeAnnotationDeploymentStrategy = "nvidia.com/deployment-strategy" KubeAnnotationDeploymentStrategy = "nvidia.com/deployment-strategy"
KubeAnnotationDeploymentRollingUpdateMaxSurge = "nvidia.com/deployment-rolling-update-max-surge"
KubeAnnotationDeploymentRollingUpdateMaxUnavailable = "nvidia.com/deployment-rolling-update-max-unavailable"
KubeAnnotationEnableStealingTrafficDebugMode = "nvidia.com/enable-stealing-traffic-debug-mode" KubeAnnotationEnableStealingTrafficDebugMode = "nvidia.com/enable-stealing-traffic-debug-mode"
KubeAnnotationEnableDebugMode = "nvidia.com/enable-debug-mode" KubeAnnotationEnableDebugMode = "nvidia.com/enable-debug-mode"
KubeAnnotationEnableDebugPodReceiveProductionTraffic = "nvidia.com/enable-debug-pod-receive-production-traffic" KubeAnnotationEnableDebugPodReceiveProductionTraffic = "nvidia.com/enable-debug-pod-receive-production-traffic"
...@@ -293,7 +295,7 @@ type ComponentReconcileResult struct { ...@@ -293,7 +295,7 @@ type ComponentReconcileResult struct {
status metav1.ConditionStatus status metav1.ConditionStatus
reason string reason string
message string message string
serviceReplicaStatus v1alpha1.ServiceReplicaStatus serviceReplicaStatus *v1alpha1.ServiceReplicaStatus
} }
func (r *DynamoComponentDeploymentReconciler) reconcileDeploymentResources(ctx context.Context, dynamoComponentDeployment *v1alpha1.DynamoComponentDeployment) (ComponentReconcileResult, error) { func (r *DynamoComponentDeploymentReconciler) reconcileDeploymentResources(ctx context.Context, dynamoComponentDeployment *v1alpha1.DynamoComponentDeployment) (ComponentReconcileResult, error) {
...@@ -305,7 +307,7 @@ func (r *DynamoComponentDeploymentReconciler) reconcileDeploymentResources(ctx c ...@@ -305,7 +307,7 @@ func (r *DynamoComponentDeploymentReconciler) reconcileDeploymentResources(ctx c
return ComponentReconcileResult{}, fmt.Errorf("failed to create or update the deployment: %w", err) return ComponentReconcileResult{}, fmt.Errorf("failed to create or update the deployment: %w", err)
} }
serviceReplicaStatus := v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus := &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: deployment.Name, ComponentName: deployment.Name,
Replicas: deployment.Status.Replicas, Replicas: deployment.Status.Replicas,
...@@ -474,9 +476,9 @@ func getLeaderWorkerSetReplicasStatus(leaderWorkerSet *leaderworkersetv1.LeaderW ...@@ -474,9 +476,9 @@ func getLeaderWorkerSetReplicasStatus(leaderWorkerSet *leaderworkersetv1.LeaderW
} }
} }
func combineLWSReplicaStatuses(serviceReplicaStatuses []v1alpha1.ServiceReplicaStatus) v1alpha1.ServiceReplicaStatus { func combineLWSReplicaStatuses(serviceReplicaStatuses []v1alpha1.ServiceReplicaStatus) *v1alpha1.ServiceReplicaStatus {
if len(serviceReplicaStatuses) == 0 { if len(serviceReplicaStatuses) == 0 {
return v1alpha1.ServiceReplicaStatus{} return nil
} }
firstServiceStatus := serviceReplicaStatuses[0] firstServiceStatus := serviceReplicaStatuses[0]
...@@ -493,7 +495,7 @@ func combineLWSReplicaStatuses(serviceReplicaStatuses []v1alpha1.ServiceReplicaS ...@@ -493,7 +495,7 @@ func combineLWSReplicaStatuses(serviceReplicaStatuses []v1alpha1.ServiceReplicaS
} }
firstServiceStatus.ReadyReplicas = &readyReplicas firstServiceStatus.ReadyReplicas = &readyReplicas
return firstServiceStatus return &firstServiceStatus
} }
// IsLeaderWorkerSetReady determines if a LeaderWorkerSet is fully ready and available // IsLeaderWorkerSetReady determines if a LeaderWorkerSet is fully ready and available
...@@ -1060,14 +1062,13 @@ func (r *DynamoComponentDeploymentReconciler) generateDeployment(ctx context.Con ...@@ -1060,14 +1062,13 @@ func (r *DynamoComponentDeploymentReconciler) generateDeployment(ctx context.Con
return return
} }
defaultMaxSurge := intstr.FromString("25%") maxSurge, maxUnavailable := getDeploymentRollingUpdateMaxSurgeAndMaxUnavailable(annotations)
defaultMaxUnavailable := intstr.FromString("25%")
strategy := appsv1.DeploymentStrategy{ strategy := appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType, Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{ RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &defaultMaxSurge, MaxSurge: &maxSurge,
MaxUnavailable: &defaultMaxUnavailable, MaxUnavailable: &maxUnavailable,
}, },
} }
...@@ -1080,30 +1081,14 @@ func (r *DynamoComponentDeploymentReconciler) generateDeployment(ctx context.Con ...@@ -1080,30 +1081,14 @@ func (r *DynamoComponentDeploymentReconciler) generateDeployment(ctx context.Con
strategy = appsv1.DeploymentStrategy{ strategy = appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType, Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{ RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &defaultMaxSurge, MaxSurge: &maxSurge,
MaxUnavailable: &defaultMaxUnavailable, MaxUnavailable: &maxUnavailable,
}, },
} }
case common.DeploymentStrategyRecreate: case common.DeploymentStrategyRecreate:
strategy = appsv1.DeploymentStrategy{ strategy = appsv1.DeploymentStrategy{
Type: appsv1.RecreateDeploymentStrategyType, Type: appsv1.RecreateDeploymentStrategyType,
} }
case common.DeploymentStrategyRampedSlowRollout:
strategy = appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &[]intstr.IntOrString{intstr.FromInt(1)}[0],
MaxUnavailable: &[]intstr.IntOrString{intstr.FromInt(0)}[0],
},
}
case common.DeploymentStrategyBestEffortControlledRollout:
strategy = appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: &[]intstr.IntOrString{intstr.FromInt(0)}[0],
MaxUnavailable: &[]intstr.IntOrString{intstr.FromString("20%")}[0],
},
}
} }
} }
...@@ -1127,6 +1112,20 @@ func (r *DynamoComponentDeploymentReconciler) generateDeployment(ctx context.Con ...@@ -1127,6 +1112,20 @@ func (r *DynamoComponentDeploymentReconciler) generateDeployment(ctx context.Con
return return
} }
func getDeploymentRollingUpdateMaxSurgeAndMaxUnavailable(annotations map[string]string) (intstr.IntOrString, intstr.IntOrString) {
maxSurge := intstr.FromString("25%")
maxUnavailable := intstr.FromString("25%")
if annotations[KubeAnnotationDeploymentRollingUpdateMaxSurge] != "" {
maxSurge = intstr.Parse(annotations[KubeAnnotationDeploymentRollingUpdateMaxSurge])
}
if annotations[KubeAnnotationDeploymentRollingUpdateMaxUnavailable] != "" {
maxUnavailable = intstr.Parse(annotations[KubeAnnotationDeploymentRollingUpdateMaxUnavailable])
}
return maxSurge, maxUnavailable
}
type generateResourceOption struct { type generateResourceOption struct {
dynamoComponentDeployment *v1alpha1.DynamoComponentDeployment dynamoComponentDeployment *v1alpha1.DynamoComponentDeployment
isStealingTrafficDebugModeEnabled bool isStealingTrafficDebugModeEnabled bool
......
...@@ -1401,7 +1401,7 @@ func Test_reconcileLeaderWorkerSetResources(t *testing.T) { ...@@ -1401,7 +1401,7 @@ func Test_reconcileLeaderWorkerSetResources(t *testing.T) {
status: metav1.ConditionTrue, status: metav1.ConditionTrue,
reason: "AllLeaderWorkerSetsReady", reason: "AllLeaderWorkerSetsReady",
message: "All LeaderWorkerSets are ready", message: "All LeaderWorkerSets are ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet, ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet,
ComponentName: "test-component-0", ComponentName: "test-component-0",
ReadyReplicas: ptr.To(int32(1)), ReadyReplicas: ptr.To(int32(1)),
...@@ -1480,7 +1480,7 @@ func Test_reconcileLeaderWorkerSetResources(t *testing.T) { ...@@ -1480,7 +1480,7 @@ func Test_reconcileLeaderWorkerSetResources(t *testing.T) {
status: metav1.ConditionFalse, status: metav1.ConditionFalse,
reason: "SomeLeaderWorkerSetsNotReady", reason: "SomeLeaderWorkerSetsNotReady",
message: "Some LeaderWorkerSets are not ready", message: "Some LeaderWorkerSets are not ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet, ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet,
ComponentName: "test-component-0", ComponentName: "test-component-0",
ReadyReplicas: ptr.To(int32(2)), ReadyReplicas: ptr.To(int32(2)),
...@@ -1559,7 +1559,7 @@ func Test_reconcileLeaderWorkerSetResources(t *testing.T) { ...@@ -1559,7 +1559,7 @@ func Test_reconcileLeaderWorkerSetResources(t *testing.T) {
status: metav1.ConditionTrue, status: metav1.ConditionTrue,
reason: "AllLeaderWorkerSetsReady", reason: "AllLeaderWorkerSetsReady",
message: "All LeaderWorkerSets are ready", message: "All LeaderWorkerSets are ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet, ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet,
ComponentName: "test-component-0", ComponentName: "test-component-0",
ReadyReplicas: ptr.To(int32(3)), ReadyReplicas: ptr.To(int32(3)),
...@@ -1704,7 +1704,7 @@ func Test_reconcileDeploymentResources(t *testing.T) { ...@@ -1704,7 +1704,7 @@ func Test_reconcileDeploymentResources(t *testing.T) {
status: metav1.ConditionTrue, status: metav1.ConditionTrue,
reason: "DeploymentReady", reason: "DeploymentReady",
message: "Deployment is ready", message: "Deployment is ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-component", ComponentName: "test-component",
Replicas: 2, Replicas: 2,
...@@ -1745,7 +1745,7 @@ func Test_reconcileDeploymentResources(t *testing.T) { ...@@ -1745,7 +1745,7 @@ func Test_reconcileDeploymentResources(t *testing.T) {
status: metav1.ConditionFalse, status: metav1.ConditionFalse,
reason: "DeploymentNotReady", reason: "DeploymentNotReady",
message: "Deployment is not ready", message: "Deployment is not ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-component", ComponentName: "test-component",
Replicas: 1, Replicas: 1,
...@@ -1842,7 +1842,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1842,7 +1842,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
wantConditionStatus metav1.ConditionStatus wantConditionStatus metav1.ConditionStatus
wantConditionReason string wantConditionReason string
wantConditionMessage string wantConditionMessage string
wantServiceReplicaStatus v1alpha1.ServiceReplicaStatus wantServiceReplicaStatus *v1alpha1.ServiceReplicaStatus
}{ }{
{ {
name: "deployment backed DCD that is unready", name: "deployment backed DCD that is unready",
...@@ -1851,7 +1851,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1851,7 +1851,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
status: metav1.ConditionFalse, status: metav1.ConditionFalse,
reason: "DeploymentNotReady", reason: "DeploymentNotReady",
message: "Deployment is not ready", message: "Deployment is not ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-component", ComponentName: "test-component",
Replicas: 1, Replicas: 1,
...@@ -1863,7 +1863,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1863,7 +1863,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
wantConditionStatus: metav1.ConditionFalse, wantConditionStatus: metav1.ConditionFalse,
wantConditionReason: "DeploymentNotReady", wantConditionReason: "DeploymentNotReady",
wantConditionMessage: "Deployment is not ready", wantConditionMessage: "Deployment is not ready",
wantServiceReplicaStatus: v1alpha1.ServiceReplicaStatus{ wantServiceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-component", ComponentName: "test-component",
Replicas: 1, Replicas: 1,
...@@ -1879,7 +1879,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1879,7 +1879,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
status: metav1.ConditionTrue, status: metav1.ConditionTrue,
reason: "DeploymentReady", reason: "DeploymentReady",
message: "Deployment is ready", message: "Deployment is ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-component", ComponentName: "test-component",
Replicas: 2, Replicas: 2,
...@@ -1891,7 +1891,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1891,7 +1891,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
wantConditionStatus: metav1.ConditionTrue, wantConditionStatus: metav1.ConditionTrue,
wantConditionReason: "DeploymentReady", wantConditionReason: "DeploymentReady",
wantConditionMessage: "Deployment is ready", wantConditionMessage: "Deployment is ready",
wantServiceReplicaStatus: v1alpha1.ServiceReplicaStatus{ wantServiceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-component", ComponentName: "test-component",
Replicas: 2, Replicas: 2,
...@@ -1907,7 +1907,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1907,7 +1907,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
status: metav1.ConditionFalse, status: metav1.ConditionFalse,
reason: "SomeLeaderWorkerSetsNotReady", reason: "SomeLeaderWorkerSetsNotReady",
message: "Some LeaderWorkerSets are not ready", message: "Some LeaderWorkerSets are not ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet, ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet,
ComponentName: "test-component-0", ComponentName: "test-component-0",
Replicas: 3, Replicas: 3,
...@@ -1918,7 +1918,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1918,7 +1918,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
wantConditionStatus: metav1.ConditionFalse, wantConditionStatus: metav1.ConditionFalse,
wantConditionReason: "SomeLeaderWorkerSetsNotReady", wantConditionReason: "SomeLeaderWorkerSetsNotReady",
wantConditionMessage: "Some LeaderWorkerSets are not ready", wantConditionMessage: "Some LeaderWorkerSets are not ready",
wantServiceReplicaStatus: v1alpha1.ServiceReplicaStatus{ wantServiceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet, ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet,
ComponentName: "test-component-0", ComponentName: "test-component-0",
Replicas: 3, Replicas: 3,
...@@ -1933,7 +1933,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1933,7 +1933,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
status: metav1.ConditionTrue, status: metav1.ConditionTrue,
reason: "AllLeaderWorkerSetsReady", reason: "AllLeaderWorkerSetsReady",
message: "All LeaderWorkerSets are ready", message: "All LeaderWorkerSets are ready",
serviceReplicaStatus: v1alpha1.ServiceReplicaStatus{ serviceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet, ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet,
ComponentName: "test-component-0", ComponentName: "test-component-0",
Replicas: 3, Replicas: 3,
...@@ -1944,7 +1944,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -1944,7 +1944,7 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
wantConditionStatus: metav1.ConditionTrue, wantConditionStatus: metav1.ConditionTrue,
wantConditionReason: "AllLeaderWorkerSetsReady", wantConditionReason: "AllLeaderWorkerSetsReady",
wantConditionMessage: "All LeaderWorkerSets are ready", wantConditionMessage: "All LeaderWorkerSets are ready",
wantServiceReplicaStatus: v1alpha1.ServiceReplicaStatus{ wantServiceReplicaStatus: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet, ComponentKind: v1alpha1.ComponentKindLeaderWorkerSet,
ComponentName: "test-component-0", ComponentName: "test-component-0",
Replicas: 3, Replicas: 3,
...@@ -2022,3 +2022,185 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) { ...@@ -2022,3 +2022,185 @@ func Test_setStatusConditionAndServiceReplicaStatus(t *testing.T) {
}) })
} }
} }
func Test_generateDeployment_Strategy(t *testing.T) {
type args struct {
annotations map[string]string
}
tests := []struct {
name string
args args
wantStrategy appsv1.DeploymentStrategy
}{
{
name: "no annotations - default RollingUpdate with default maxSurge and maxUnavailable",
args: args{
annotations: nil,
},
wantStrategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: ptr.To(intstr.FromString("25%")),
MaxUnavailable: ptr.To(intstr.FromString("25%")),
},
},
},
{
name: "deployment-strategy annotation with Recreate - strategy is Recreate",
args: args{
annotations: map[string]string{
KubeAnnotationDeploymentStrategy: "Recreate",
},
},
wantStrategy: appsv1.DeploymentStrategy{
Type: appsv1.RecreateDeploymentStrategyType,
},
},
{
name: "deployment-strategy Recreate with maxSurge/maxUnavailable - maxSurge/maxUnavailable are ignored",
args: args{
annotations: map[string]string{
KubeAnnotationDeploymentStrategy: "Recreate",
KubeAnnotationDeploymentRollingUpdateMaxSurge: "50%",
KubeAnnotationDeploymentRollingUpdateMaxUnavailable: "30%",
},
},
wantStrategy: appsv1.DeploymentStrategy{
Type: appsv1.RecreateDeploymentStrategyType,
},
},
{
name: "deployment-strategy RollingUpdate with only maxSurge",
args: args{
annotations: map[string]string{
KubeAnnotationDeploymentStrategy: "RollingUpdate",
KubeAnnotationDeploymentRollingUpdateMaxSurge: "50%",
},
},
wantStrategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: ptr.To(intstr.FromString("50%")),
MaxUnavailable: ptr.To(intstr.FromString("25%")),
},
},
},
{
name: "deployment-strategy RollingUpdate with only maxUnavailable",
args: args{
annotations: map[string]string{
KubeAnnotationDeploymentStrategy: "RollingUpdate",
KubeAnnotationDeploymentRollingUpdateMaxUnavailable: "10%",
},
},
wantStrategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: ptr.To(intstr.FromString("25%")),
MaxUnavailable: ptr.To(intstr.FromString("10%")),
},
},
},
{
name: "deployment-strategy RollingUpdate with both maxSurge and maxUnavailable",
args: args{
annotations: map[string]string{
KubeAnnotationDeploymentStrategy: "RollingUpdate",
KubeAnnotationDeploymentRollingUpdateMaxSurge: "40%",
KubeAnnotationDeploymentRollingUpdateMaxUnavailable: "20%",
},
},
wantStrategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: ptr.To(intstr.FromString("40%")),
MaxUnavailable: ptr.To(intstr.FromString("20%")),
},
},
},
{
name: "deployment-strategy RollingUpdate with integer maxSurge and maxUnavailable (not percentages)",
args: args{
annotations: map[string]string{
KubeAnnotationDeploymentStrategy: "RollingUpdate",
KubeAnnotationDeploymentRollingUpdateMaxSurge: "1",
KubeAnnotationDeploymentRollingUpdateMaxUnavailable: "0",
},
},
wantStrategy: appsv1.DeploymentStrategy{
Type: appsv1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &appsv1.RollingUpdateDeployment{
MaxSurge: ptr.To(intstr.FromInt(1)),
MaxUnavailable: ptr.To(intstr.FromInt(0)),
},
},
},
}
// Initialize scheme & add API types
s := scheme.Scheme
if err := v1alpha1.AddToScheme(s); err != nil {
t.Fatalf("Failed to add v1alpha1 to scheme: %v", err)
}
if err := corev1.AddToScheme(s); err != nil {
t.Fatalf("Failed to add corev1 to scheme: %v", err)
}
if err := appsv1.AddToScheme(s); err != nil {
t.Fatalf("Failed to add appsv1 to scheme: %v", err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := gomega.NewGomegaWithT(t)
dcd := &v1alpha1.DynamoComponentDeployment{
ObjectMeta: metav1.ObjectMeta{
Name: "test-deployment-strategy",
Namespace: "default",
},
Spec: v1alpha1.DynamoComponentDeploymentSpec{
BackendFramework: string(dynamo.BackendFrameworkVLLM),
DynamoComponentDeploymentSharedSpec: v1alpha1.DynamoComponentDeploymentSharedSpec{
ServiceName: "test-service",
DynamoNamespace: ptr.To("default"),
ComponentType: string(commonconsts.ComponentTypeDecode),
Replicas: ptr.To(int32(1)),
Annotations: tt.args.annotations,
ExtraPodSpec: &v1alpha1.ExtraPodSpec{
MainContainer: &corev1.Container{
Image: "test-image:latest",
},
},
},
},
}
fakeKubeClient := fake.NewClientBuilder().
WithScheme(s).
WithObjects(dcd).
Build()
recorder := record.NewFakeRecorder(100)
reconciler := &DynamoComponentDeploymentReconciler{
Client: fakeKubeClient,
Recorder: recorder,
Config: controller_common.Config{},
DockerSecretRetriever: &mockDockerSecretRetriever{
GetSecretsFunc: func(namespace, imageName string) ([]string, error) {
return []string{}, nil
},
},
}
opt := generateResourceOption{
dynamoComponentDeployment: dcd,
}
deployment, toDelete, err := reconciler.generateDeployment(context.Background(), opt)
g.Expect(err).NotTo(gomega.HaveOccurred())
g.Expect(toDelete).To(gomega.BeFalse())
g.Expect(deployment).NotTo(gomega.BeNil())
g.Expect(deployment.Spec.Strategy).To(gomega.Equal(tt.wantStrategy))
})
}
}
...@@ -706,7 +706,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -706,7 +706,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-frontend-deployment", ComponentName: "test-dgd-frontend-deployment",
Replicas: 2, Replicas: 2,
...@@ -766,7 +766,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -766,7 +766,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-frontend-deployment", ComponentName: "test-dgd-frontend-deployment",
Replicas: 2, Replicas: 2,
...@@ -838,7 +838,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -838,7 +838,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-frontend-deployment", ComponentName: "test-dgd-frontend-deployment",
Replicas: 1, Replicas: 1,
...@@ -867,7 +867,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -867,7 +867,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-decode-deployment", ComponentName: "test-dgd-decode-deployment",
Replicas: 2, Replicas: 2,
...@@ -896,7 +896,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -896,7 +896,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-prefill-deployment", ComponentName: "test-dgd-prefill-deployment",
Replicas: 3, Replicas: 3,
...@@ -984,7 +984,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -984,7 +984,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-frontend-deployment", ComponentName: "test-dgd-frontend-deployment",
Replicas: 1, Replicas: 1,
...@@ -1013,7 +1013,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -1013,7 +1013,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-decode-deployment", ComponentName: "test-dgd-decode-deployment",
Replicas: 2, Replicas: 2,
...@@ -1042,7 +1042,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -1042,7 +1042,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionTrue, Status: metav1.ConditionTrue,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-prefill-deployment", ComponentName: "test-dgd-prefill-deployment",
Replicas: 3, Replicas: 3,
...@@ -1124,7 +1124,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -1124,7 +1124,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-frontend-deployment", ComponentName: "test-dgd-frontend-deployment",
Replicas: 1, Replicas: 1,
...@@ -1153,7 +1153,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) { ...@@ -1153,7 +1153,7 @@ func Test_reconcileDynamoComponentsDeployments(t *testing.T) {
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
}, },
}, },
Service: v1alpha1.ServiceReplicaStatus{ Service: &v1alpha1.ServiceReplicaStatus{
ComponentKind: v1alpha1.ComponentKindDeployment, ComponentKind: v1alpha1.ComponentKindDeployment,
ComponentName: "test-dgd-decode-deployment", ComponentName: "test-dgd-decode-deployment",
Replicas: 2, Replicas: 2,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment