Skip to content

Commit 7033f41

Browse files
feat: Add JVM optimization settings to workload scaling policy (#670)
1 parent d4da95d commit 7033f41

File tree

8 files changed

+686
-65
lines changed

8 files changed

+686
-65
lines changed

castai/resource_workload_scaling_policy.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const (
5050
FieldRolloutBehaviorType = "type"
5151
FieldRolloutBehaviorNoDisruptionType = "NO_DISRUPTION"
5252
FieldRolloutBehaviorPreferOneByOneType = "prefer_one_by_one"
53+
FieldJVM = "jvm"
5354
FieldPredictiveScaling = "predictive_scaling"
5455
FieldMemoryEvent = "memory_event"
5556
FieldApplyType = "apply_type"
@@ -320,6 +321,31 @@ It can be either:
320321
},
321322
},
322323
},
324+
FieldJVM: {
325+
Type: schema.TypeList,
326+
Optional: true,
327+
MaxItems: 1,
328+
Description: "JVM optimization settings.",
329+
Elem: &schema.Resource{
330+
Schema: map[string]*schema.Schema{
331+
"memory": {
332+
Type: schema.TypeList,
333+
Optional: true,
334+
MaxItems: 1,
335+
Description: "JVM memory optimization settings.",
336+
Elem: &schema.Resource{
337+
Schema: map[string]*schema.Schema{
338+
"optimization": {
339+
Type: schema.TypeBool,
340+
Optional: true,
341+
Description: "Defines whether JVM memory optimization is enabled. When enabled, JVM heap size will be adjusted based on JVM metrics, if available.",
342+
},
343+
},
344+
},
345+
},
346+
},
347+
},
348+
},
323349
},
324350
Timeouts: &schema.ResourceTimeout{
325351
Create: schema.DefaultTimeout(createTimeout),
@@ -610,6 +636,8 @@ func resourceWorkloadScalingPolicyCreate(ctx context.Context, d *schema.Resource
610636

611637
req.RecommendationPolicies.RolloutBehavior = toRolloutBehavior(toSection(d, FieldRolloutBehavior))
612638

639+
req.RecommendationPolicies.Jvm = toJvm(toSection(d, FieldJVM))
640+
613641
req.RecommendationPolicies.ExcludedContainers = toExcludedContainers(d)
614642

615643
ar, err := toAssignmentRules(toSection(d, FieldAssignmentRules))
@@ -750,6 +778,9 @@ func fetchScalingPolicy(ctx context.Context, d *schema.ResourceData, meta any) (
750778
if err := d.Set(FieldRolloutBehavior, toRolloutBehaviorMap(sp.RecommendationPolicies.RolloutBehavior)); err != nil {
751779
return nil, fmt.Errorf("setting rollout behavior: %w", err)
752780
}
781+
if err := d.Set(FieldJVM, toJvmMap(sp.RecommendationPolicies.Jvm)); err != nil {
782+
return nil, fmt.Errorf("setting jvm: %w", err)
783+
}
753784

754785
if err := d.Set(FieldAssignmentRules, toAssignmentRulesMap(getResourceFrom(d, FieldAssignmentRules), sp.AssignmentRules)); err != nil {
755786
return nil, fmt.Errorf("setting assignment rules: %w", err)
@@ -788,6 +819,7 @@ func updateScalingPolicy(ctx context.Context, d *schema.ResourceData, meta any)
788819
FieldAssignmentRules,
789820
FieldPredictiveScaling,
790821
FieldRolloutBehavior,
822+
FieldJVM,
791823
FieldExcludedContainers,
792824
) {
793825
tflog.Info(ctx, "scaling policy up to date")
@@ -824,6 +856,7 @@ func updateScalingPolicy(ctx context.Context, d *schema.ResourceData, meta any)
824856
Confidence: toConfidence(toSection(d, FieldConfidence)),
825857
PredictiveScaling: toPredictiveScaling(toSection(d, FieldPredictiveScaling)),
826858
RolloutBehavior: toRolloutBehavior(toSection(d, FieldRolloutBehavior)),
859+
Jvm: toJvm(toSection(d, FieldJVM)),
827860
ExcludedContainers: toExcludedContainers(d),
828861
},
829862
}
@@ -1459,6 +1492,36 @@ func toRolloutBehaviorMap(s *sdk.WorkloadoptimizationV1RolloutBehaviorSettings)
14591492
return []map[string]any{m}
14601493
}
14611494

1495+
func toJvm(m map[string]any) *sdk.WorkloadoptimizationV1JVMSettings {
1496+
if len(m) == 0 {
1497+
return nil
1498+
}
1499+
result := &sdk.WorkloadoptimizationV1JVMSettings{}
1500+
if mem := getFirstElem(m, "memory"); mem != nil {
1501+
result.Memory = &sdk.WorkloadoptimizationV1JVMMemorySettings{}
1502+
if v, ok := mem["optimization"].(bool); ok {
1503+
result.Memory.Optimization = v
1504+
}
1505+
}
1506+
return result
1507+
}
1508+
1509+
func toJvmMap(s *sdk.WorkloadoptimizationV1JVMSettings) []map[string]any {
1510+
if s == nil {
1511+
return nil
1512+
}
1513+
m := map[string]any{}
1514+
if s.Memory != nil {
1515+
m["memory"] = []map[string]any{{
1516+
"optimization": s.Memory.Optimization,
1517+
}}
1518+
}
1519+
if len(m) == 0 {
1520+
return nil
1521+
}
1522+
return []map[string]any{m}
1523+
}
1524+
14621525
func getWorkloadScalingPolicyByName(ctx context.Context, client sdk.ClientWithResponsesInterface, clusterID, name string) (*sdk.WorkloadoptimizationV1WorkloadScalingPolicy, error) {
14631526
list, err := client.WorkloadOptimizationAPIListWorkloadScalingPoliciesWithResponse(ctx, clusterID)
14641527
if e := checkIfRetryable(list, err); e != nil {

castai/resource_workload_scaling_policy_test.go

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func TestAccGKE_ResourceWorkloadScalingPolicy(t *testing.T) {
123123
resource.TestCheckResourceAttr(resourceName, "predictive_scaling.0.cpu.0.enabled", "true"),
124124
// Requires workload-autoscaler from v0.35.3
125125
resource.TestCheckResourceAttr(resourceName, "rollout_behavior.0.type", "NO_DISRUPTION"),
126+
resource.TestCheckResourceAttr(resourceName, "jvm.0.memory.0.optimization", "true"),
126127
),
127128
},
128129
},
@@ -392,6 +393,11 @@ func scalingPolicyConfigUpdated(clusterName, projectID, name string) string {
392393
confidence {
393394
threshold = 0.6
394395
}
396+
jvm {
397+
memory {
398+
optimization = true
399+
}
400+
}
395401
}`, updatedName)
396402

397403
return ConfigCompose(clusterComponentsConfig(clusterName, projectID, name), cfg)
@@ -831,6 +837,94 @@ func Test_toRolloutBehaviorMap(t *testing.T) {
831837
}
832838
}
833839

840+
func Test_toJvm(t *testing.T) {
841+
tests := map[string]struct {
842+
args map[string]any
843+
exp *sdk.WorkloadoptimizationV1JVMSettings
844+
}{
845+
"should return jvm settings with memory optimization enabled": {
846+
args: map[string]any{
847+
"memory": []any{
848+
map[string]any{
849+
"optimization": true,
850+
},
851+
},
852+
},
853+
exp: &sdk.WorkloadoptimizationV1JVMSettings{
854+
Memory: &sdk.WorkloadoptimizationV1JVMMemorySettings{
855+
Optimization: true,
856+
},
857+
},
858+
},
859+
"should return jvm settings with memory optimization disabled": {
860+
args: map[string]any{
861+
"memory": []any{
862+
map[string]any{
863+
"optimization": false,
864+
},
865+
},
866+
},
867+
exp: &sdk.WorkloadoptimizationV1JVMSettings{
868+
Memory: &sdk.WorkloadoptimizationV1JVMMemorySettings{
869+
Optimization: false,
870+
},
871+
},
872+
},
873+
"should return nil on empty map": {
874+
args: map[string]any{},
875+
exp: nil,
876+
},
877+
"should return nil on nil map": {
878+
args: nil,
879+
exp: nil,
880+
},
881+
}
882+
for name, tt := range tests {
883+
t.Run(name, func(t *testing.T) {
884+
r := require.New(t)
885+
got := toJvm(tt.args)
886+
r.Equal(tt.exp, got)
887+
})
888+
}
889+
}
890+
891+
func Test_toJvmMap(t *testing.T) {
892+
tests := map[string]struct {
893+
args *sdk.WorkloadoptimizationV1JVMSettings
894+
exp []map[string]any
895+
}{
896+
"should return jvm map with memory optimization": {
897+
args: &sdk.WorkloadoptimizationV1JVMSettings{
898+
Memory: &sdk.WorkloadoptimizationV1JVMMemorySettings{
899+
Optimization: true,
900+
},
901+
},
902+
exp: []map[string]any{
903+
{
904+
"memory": []map[string]any{{
905+
"optimization": true,
906+
}},
907+
},
908+
},
909+
},
910+
"should return nil for nil input": {
911+
args: nil,
912+
exp: nil,
913+
},
914+
"should return nil for empty settings": {
915+
args: &sdk.WorkloadoptimizationV1JVMSettings{},
916+
exp: nil,
917+
},
918+
}
919+
for name, tt := range tests {
920+
t.Run(name, func(t *testing.T) {
921+
r := require.New(t)
922+
got := toJvmMap(tt.args)
923+
r.Equal(tt.exp, got)
924+
})
925+
}
926+
}
927+
834928
func Test_resourceWorkloadScalingPolicyCreate(t *testing.T) {
835929
organizationId := "63d2af53-9a42-4968-be1e-39316ebfd8d4"
836930
clusterId := "4e4cd9eb-82eb-407e-a926-e5fef81cab50"
@@ -987,7 +1081,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
9871081
"should map limit strategy with only_if_original_exist true": {
9881082
previousCfg: map[string]any{},
9891083
policies: sdk.WorkloadoptimizationV1ResourcePolicies{
990-
Function: sdk.QUANTILE,
1084+
Function: sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
9911085
Args: []string{"0.9"},
9921086
Overhead: 0.1,
9931087
Limit: &sdk.WorkloadoptimizationV1ResourceLimitStrategy{
@@ -998,7 +1092,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
9981092
},
9991093
expected: []map[string]any{
10001094
{
1001-
"function": sdk.QUANTILE,
1095+
"function": sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
10021096
"args": []string{"0.9"},
10031097
"overhead": 0.1,
10041098
"min": (*float64)(nil),
@@ -1016,7 +1110,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
10161110
"should map limit strategy with only_if_original_exist false": {
10171111
previousCfg: map[string]any{},
10181112
policies: sdk.WorkloadoptimizationV1ResourcePolicies{
1019-
Function: sdk.MAX,
1113+
Function: sdk.WorkloadoptimizationV1ResourcePoliciesFunctionMAX,
10201114
Overhead: 0.15,
10211115
Limit: &sdk.WorkloadoptimizationV1ResourceLimitStrategy{
10221116
Type: sdk.WorkloadoptimizationV1ResourceLimitStrategyTypeNOLIMIT,
@@ -1025,7 +1119,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
10251119
},
10261120
expected: []map[string]any{
10271121
{
1028-
"function": sdk.MAX,
1122+
"function": sdk.WorkloadoptimizationV1ResourcePoliciesFunctionMAX,
10291123
"args": []string(nil),
10301124
"overhead": 0.15,
10311125
"min": (*float64)(nil),
@@ -1042,7 +1136,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
10421136
"should map limit strategy with only_if_original_lower true": {
10431137
previousCfg: map[string]any{},
10441138
policies: sdk.WorkloadoptimizationV1ResourcePolicies{
1045-
Function: sdk.QUANTILE,
1139+
Function: sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
10461140
Args: []string{"0.95"},
10471141
Overhead: 0.2,
10481142
Limit: &sdk.WorkloadoptimizationV1ResourceLimitStrategy{
@@ -1052,7 +1146,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
10521146
},
10531147
expected: []map[string]any{
10541148
{
1055-
"function": sdk.QUANTILE,
1149+
"function": sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
10561150
"args": []string{"0.95"},
10571151
"overhead": 0.2,
10581152
"min": (*float64)(nil),
@@ -1069,7 +1163,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
10691163
"should map limit strategy with only_if_original_lower false": {
10701164
previousCfg: map[string]any{},
10711165
policies: sdk.WorkloadoptimizationV1ResourcePolicies{
1072-
Function: sdk.QUANTILE,
1166+
Function: sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
10731167
Args: []string{"0.5"},
10741168
Overhead: 0.05,
10751169
Limit: &sdk.WorkloadoptimizationV1ResourceLimitStrategy{
@@ -1080,7 +1174,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
10801174
},
10811175
expected: []map[string]any{
10821176
{
1083-
"function": sdk.QUANTILE,
1177+
"function": sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
10841178
"args": []string{"0.5"},
10851179
"overhead": 0.05,
10861180
"min": (*float64)(nil),
@@ -1098,7 +1192,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
10981192
"should map limit strategy with both only_if_original_exist and only_if_original_lower": {
10991193
previousCfg: map[string]any{},
11001194
policies: sdk.WorkloadoptimizationV1ResourcePolicies{
1101-
Function: sdk.MAX,
1195+
Function: sdk.WorkloadoptimizationV1ResourcePoliciesFunctionMAX,
11021196
Overhead: 0.3,
11031197
Limit: &sdk.WorkloadoptimizationV1ResourceLimitStrategy{
11041198
Type: sdk.WorkloadoptimizationV1ResourceLimitStrategyTypeMULTIPLIER,
@@ -1109,7 +1203,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
11091203
},
11101204
expected: []map[string]any{
11111205
{
1112-
"function": sdk.MAX,
1206+
"function": sdk.WorkloadoptimizationV1ResourcePoliciesFunctionMAX,
11131207
"args": []string(nil),
11141208
"overhead": 0.3,
11151209
"min": (*float64)(nil),
@@ -1128,7 +1222,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
11281222
"should map limit strategy without only_if flags": {
11291223
previousCfg: map[string]any{},
11301224
policies: sdk.WorkloadoptimizationV1ResourcePolicies{
1131-
Function: sdk.QUANTILE,
1225+
Function: sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
11321226
Args: []string{"0.8"},
11331227
Overhead: 0.12,
11341228
Limit: &sdk.WorkloadoptimizationV1ResourceLimitStrategy{
@@ -1138,7 +1232,7 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
11381232
},
11391233
expected: []map[string]any{
11401234
{
1141-
"function": sdk.QUANTILE,
1235+
"function": sdk.WorkloadoptimizationV1ResourcePoliciesFunctionQUANTILE,
11421236
"args": []string{"0.8"},
11431237
"overhead": 0.12,
11441238
"min": (*float64)(nil),
@@ -1155,13 +1249,13 @@ func Test_toWorkloadScalingPoliciesMap(t *testing.T) {
11551249
"should not include limit when nil": {
11561250
previousCfg: map[string]any{},
11571251
policies: sdk.WorkloadoptimizationV1ResourcePolicies{
1158-
Function: sdk.MAX,
1252+
Function: sdk.WorkloadoptimizationV1ResourcePoliciesFunctionMAX,
11591253
Overhead: 0.1,
11601254
Limit: nil,
11611255
},
11621256
expected: []map[string]any{
11631257
{
1164-
"function": sdk.MAX,
1258+
"function": sdk.WorkloadoptimizationV1ResourcePoliciesFunctionMAX,
11651259
"args": []string(nil),
11661260
"overhead": 0.1,
11671261
"min": (*float64)(nil),

0 commit comments

Comments
 (0)