diff --git a/castai/resource_workload_scaling_policy.go b/castai/resource_workload_scaling_policy.go index 9f6f0a1a..fc5f6c1c 100644 --- a/castai/resource_workload_scaling_policy.go +++ b/castai/resource_workload_scaling_policy.go @@ -125,6 +125,21 @@ func resourceWorkloadScalingPolicy() *schema.Resource { }, }, }, + "anti_affinity": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "consider_anti_affinity": { + Type: schema.TypeBool, + Optional: true, + Description: `Defines if anti-affinity should be considered when scaling the workload. + If enabled, requiring host ports, or having anti-affinity on hostname will force all recommendations to be deferred.`, + }, + }, + }, + }, }, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(15 * time.Second), @@ -218,6 +233,8 @@ func resourceWorkloadScalingPolicyCreate(ctx context.Context, d *schema.Resource req.RecommendationPolicies.MemoryEvent = toMemoryEvent(toSection(d, "memory_event")) + req.RecommendationPolicies.AntiAffinity = toAntiAffinity(toSection(d, "anti_affinity")) + resp, err := client.WorkloadOptimizationAPICreateWorkloadScalingPolicyWithResponse(ctx, clusterID, req) if checkErr := sdk.CheckOKResponse(resp, err); checkErr != nil { return diag.FromErr(checkErr) @@ -272,6 +289,9 @@ func resourceWorkloadScalingPolicyRead(ctx context.Context, d *schema.ResourceDa if err := d.Set("memory_event", toMemoryEventMap(sp.RecommendationPolicies.MemoryEvent)); err != nil { return diag.FromErr(fmt.Errorf("setting memory event: %w", err)) } + if err := d.Set("anti_affinity", toAntiAffinityMap(sp.RecommendationPolicies.AntiAffinity)); err != nil { + return diag.FromErr(fmt.Errorf("setting anti-affinity: %w", err)) + } return nil } @@ -286,6 +306,7 @@ func resourceWorkloadScalingPolicyUpdate(ctx context.Context, d *schema.Resource "startup", "downscaling", "memory_event", + "anti_affinity", ) { tflog.Info(ctx, "scaling policy up to date") return nil @@ -303,6 +324,7 @@ func resourceWorkloadScalingPolicyUpdate(ctx context.Context, d *schema.Resource Startup: toStartup(toSection(d, "startup")), Downscaling: toDownscaling(toSection(d, "downscaling")), MemoryEvent: toMemoryEvent(toSection(d, "memory_event")), + AntiAffinity: toAntiAffinity(toSection(d, "anti_affinity")), }, } @@ -542,3 +564,35 @@ func toMemoryEventMap(s *sdk.WorkloadoptimizationV1MemoryEventSettings) []map[st return []map[string]any{m} } + +func toAntiAffinity(antiAffinity map[string]any) *sdk.WorkloadoptimizationV1AntiAffinitySettings { + if len(antiAffinity) == 0 { + return nil + } + + result := &sdk.WorkloadoptimizationV1AntiAffinitySettings{} + + if v, ok := antiAffinity["consider_anti_affinity"].(bool); ok { + result.ConsiderAntiAffinity = lo.ToPtr(v) + } + + return result +} + +func toAntiAffinityMap(s *sdk.WorkloadoptimizationV1AntiAffinitySettings) []map[string]any { + if s == nil { + return nil + } + + m := map[string]any{} + + if s.ConsiderAntiAffinity != nil { + m["consider_anti_affinity"] = *s.ConsiderAntiAffinity + } + + if len(m) == 0 { + return nil + } + + return []map[string]any{m} +} diff --git a/castai/resource_workload_scaling_policy_test.go b/castai/resource_workload_scaling_policy_test.go index 50f9e5f4..26e26be9 100644 --- a/castai/resource_workload_scaling_policy_test.go +++ b/castai/resource_workload_scaling_policy_test.go @@ -76,6 +76,7 @@ func TestAccResourceWorkloadScalingPolicy(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "startup.0.period_seconds", "123"), resource.TestCheckResourceAttr(resourceName, "downscaling.0.apply_type", "DEFERRED"), resource.TestCheckResourceAttr(resourceName, "memory_event.0.apply_type", "DEFERRED"), + resource.TestCheckResourceAttr(resourceName, "anti_affinity.0.consider_anti_affinity", "true"), ), }, }, @@ -151,6 +152,9 @@ func scalingPolicyConfigUpdated(clusterName, projectID, name string) string { } memory_event { apply_type = "DEFERRED" + } + anti_affinity { + consider_anti_affinity = true } }`, updatedName) diff --git a/castai/sdk/api.gen.go b/castai/sdk/api.gen.go index 4f7b641e..f9737981 100644 --- a/castai/sdk/api.gen.go +++ b/castai/sdk/api.gen.go @@ -1429,7 +1429,9 @@ type CastaiUsersV1beta1Organization struct { // OrganizationMetadata describes organization metadata. Metadata *CastaiUsersV1beta1OrganizationMetadata `json:"metadata,omitempty"` - // name of the organization. + // name of the organization. Name of the organization must start with a + // letter or a number, followed by letters, numbers, underscores, hyphens, + // spaces and periods. The name must end with a letter or a number. Name string `json:"name"` } @@ -3282,6 +3284,13 @@ type WorkloadoptimizationV1AggregatedMetrics struct { P75 float64 `json:"p75"` } +// WorkloadoptimizationV1AntiAffinitySettings defines model for workloadoptimization.v1.AntiAffinitySettings. +type WorkloadoptimizationV1AntiAffinitySettings struct { + // Defines if anti-affinity should be considered when scaling the workload. + // When true, requiring host ports, or having anti-affinity on hostname will force all recommendations to be deferred. + ConsiderAntiAffinity *bool `json:"considerAntiAffinity"` +} + // WorkloadoptimizationV1ApplyType defines model for workloadoptimization.v1.ApplyType. type WorkloadoptimizationV1ApplyType string @@ -3560,8 +3569,9 @@ type WorkloadoptimizationV1RecommendationEventType string // WorkloadoptimizationV1RecommendationPolicies defines model for workloadoptimization.v1.RecommendationPolicies. type WorkloadoptimizationV1RecommendationPolicies struct { - Cpu WorkloadoptimizationV1ResourcePolicies `json:"cpu"` - Downscaling *WorkloadoptimizationV1DownscalingSettings `json:"downscaling,omitempty"` + AntiAffinity *WorkloadoptimizationV1AntiAffinitySettings `json:"antiAffinity,omitempty"` + Cpu WorkloadoptimizationV1ResourcePolicies `json:"cpu"` + Downscaling *WorkloadoptimizationV1DownscalingSettings `json:"downscaling,omitempty"` // Defines possible options for workload management. // READ_ONLY - workload watched (metrics collected), but no actions may be performed by CAST AI. @@ -3770,6 +3780,7 @@ type WorkloadoptimizationV1UpdateWorkloadV2 struct { // WorkloadoptimizationV1VPAConfig defines model for workloadoptimization.v1.VPAConfig. type WorkloadoptimizationV1VPAConfig struct { + AntiAffinity WorkloadoptimizationV1AntiAffinitySettings `json:"antiAffinity"` ContainerConstraints []WorkloadoptimizationV1ContainerConstraints `json:"containerConstraints"` Cpu WorkloadoptimizationV1ResourceConfig `json:"cpu"` @@ -3783,6 +3794,7 @@ type WorkloadoptimizationV1VPAConfig struct { // WorkloadoptimizationV1VPAConfigUpdate defines model for workloadoptimization.v1.VPAConfigUpdate. type WorkloadoptimizationV1VPAConfigUpdate struct { + AntiAffinity *WorkloadoptimizationV1AntiAffinitySettings `json:"antiAffinity,omitempty"` ContainerConfig *[]WorkloadoptimizationV1ContainerConfigUpdate `json:"containerConfig,omitempty"` Cpu *WorkloadoptimizationV1WorkloadResourceConfigUpdate `json:"cpu,omitempty"` @@ -3843,6 +3855,7 @@ type WorkloadoptimizationV1Workload struct { // WorkloadoptimizationV1WorkloadConfig defines model for workloadoptimization.v1.WorkloadConfig. type WorkloadoptimizationV1WorkloadConfig struct { + AntiAffinity WorkloadoptimizationV1AntiAffinitySettings `json:"antiAffinity"` ContainerConstraints []WorkloadoptimizationV1ContainerConstraints `json:"containerConstraints"` Cpu WorkloadoptimizationV1ResourceConfig `json:"cpu"` @@ -3856,6 +3869,7 @@ type WorkloadoptimizationV1WorkloadConfig struct { // WorkloadoptimizationV1WorkloadConfigUpdate defines model for workloadoptimization.v1.WorkloadConfigUpdate. type WorkloadoptimizationV1WorkloadConfigUpdate struct { + AntiAffinity *WorkloadoptimizationV1AntiAffinitySettings `json:"antiAffinity,omitempty"` ContainerConfig *[]WorkloadoptimizationV1ContainerConfigUpdate `json:"containerConfig,omitempty"` Cpu *WorkloadoptimizationV1WorkloadResourceConfigUpdate `json:"cpu,omitempty"` diff --git a/docs/resources/workload_scaling_policy.md b/docs/resources/workload_scaling_policy.md index f796ccd3..2aca9004 100644 --- a/docs/resources/workload_scaling_policy.md +++ b/docs/resources/workload_scaling_policy.md @@ -40,9 +40,12 @@ resource "castai_workload_scaling_policy" "services" { downscaling { apply_type = "DEFERRED" } - downscaling { + memory_event { apply_type = "IMMEDIATE" } + anti_affinity { + consider_anti_affinity = "IMMEDIATE" + } } ``` @@ -64,6 +67,7 @@ resource "castai_workload_scaling_policy" "services" { ### Optional +- `anti_affinity` (Block List, Max: 1) (see [below for nested schema](#nestedblock--anti_affinity)) - `downscaling` (Block List, Max: 1) (see [below for nested schema](#nestedblock--downscaling)) - `memory_event` (Block List, Max: 1) (see [below for nested schema](#nestedblock--memory_event)) - `startup` (Block List, Max: 1) (see [below for nested schema](#nestedblock--startup)) @@ -101,6 +105,15 @@ Optional: - `overhead` (Number) Overhead for the recommendation, e.g. `0.1` will result in 10% higher recommendation + +### Nested Schema for `anti_affinity` + +Optional: + +- `consider_anti_affinity` (Boolean) Defines if anti-affinity should be considered when scaling the workload. + If enabled, requiring host ports, or having anti-affinity on hostname will force all recommendations to be deferred. + + ### Nested Schema for `downscaling` diff --git a/examples/resources/castai_workload_scaling_policy/resource.tf b/examples/resources/castai_workload_scaling_policy/resource.tf index 64df008f..e07c1118 100644 --- a/examples/resources/castai_workload_scaling_policy/resource.tf +++ b/examples/resources/castai_workload_scaling_policy/resource.tf @@ -23,7 +23,10 @@ resource "castai_workload_scaling_policy" "services" { downscaling { apply_type = "DEFERRED" } - downscaling { + memory_event { apply_type = "IMMEDIATE" } + anti_affinity { + consider_anti_affinity = "IMMEDIATE" + } } \ No newline at end of file