diff --git a/Makefile b/Makefile
index 0db9fd99..7780869e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+
+
default: build
init-examples:
@@ -16,7 +18,7 @@ init-examples:
generate-sdk:
@echo "==> Generating castai sdk client"
- @API_TAGS=ExternalClusterAPI,PoliciesAPI,NodeConfigurationAPI,NodeTemplatesAPI,AuthTokenAPI,ScheduledRebalancingAPI,InventoryAPI,UsersAPI,OperationsAPI go generate castai/sdk/generate.go
+ @API_TAGS=ExternalClusterAPI,PoliciesAPI,NodeConfigurationAPI,NodeTemplatesAPI,AuthTokenAPI,ScheduledRebalancingAPI,InventoryAPI,UsersAPI,OperationsAPI,EvictorAPI go generate castai/sdk/generate.go
# The following command also rewrites existing documentation
generate-docs:
diff --git a/castai/provider.go b/castai/provider.go
index a6c87cc0..5c807b46 100644
--- a/castai/provider.go
+++ b/castai/provider.go
@@ -39,6 +39,7 @@ func Provider(version string) *schema.Provider {
"castai_gke_cluster": resourceGKECluster(),
"castai_aks_cluster": resourceAKSCluster(),
"castai_autoscaler": resourceAutoscaler(),
+ "castai_evictor_advanced_config": resourceEvictionConfig(),
"castai_node_template": resourceNodeTemplate(),
"castai_rebalancing_schedule": resourceRebalancingSchedule(),
"castai_rebalancing_job": resourceRebalancingJob(),
diff --git a/castai/resource_eviction_config.go b/castai/resource_eviction_config.go
new file mode 100644
index 00000000..27494e10
--- /dev/null
+++ b/castai/resource_eviction_config.go
@@ -0,0 +1,579 @@
+package castai
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "github.com/castai/terraform-provider-castai/castai/sdk"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+ "github.com/samber/lo"
+ "log"
+ "time"
+)
+
+const (
+ FieldEvictorAdvancedConfig = "evictor_advanced_config"
+ FieldEvictionConfig = "eviction_config"
+ FieldNodeSelector = "node_selector"
+ FieldPodSelector = "pod_selector"
+ FieldEvictionSettings = "settings"
+ FieldEvictionOptionDisabled = "removal_disabled"
+ FieldEvictionOptionAggressive = "aggressive"
+ FieldEvictionOptionDisposable = "disposable"
+ FieldPodSelectorKind = "kind"
+ FieldPodSelectorNamespace = "namespace"
+ FieldMatchLabels = "match_labels"
+ FieldMatchExpressions = "match_expressions"
+ FieldMatchExpressionKey = "key"
+ FieldMatchExpressionOp = "operator"
+ FieldMatchExpressionVal = "values"
+)
+
+func resourceEvictionConfig() *schema.Resource {
+ return &schema.Resource{
+ ReadContext: resourceEvictionConfigRead,
+ CreateContext: resourceEvictionConfigCreate,
+ UpdateContext: resourceEvictionConfigUpdate,
+ DeleteContext: resourceEvictionConfigDelete,
+ Description: "CAST AI eviction config resource to manage evictor properties ",
+
+ Timeouts: &schema.ResourceTimeout{
+ Create: schema.DefaultTimeout(2 * time.Minute),
+ Update: schema.DefaultTimeout(2 * time.Minute),
+ },
+ Schema: map[string]*schema.Schema{
+ FieldClusterId: {
+ Type: schema.TypeString,
+ Optional: true,
+ ValidateDiagFunc: validation.ToDiagFunc(validation.IsUUID),
+ Description: "CAST AI cluster id.",
+ },
+ FieldEvictorAdvancedConfig: {
+ Type: schema.TypeList,
+ Description: "evictor advanced configuration to target specific node/pod",
+ Required: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ FieldPodSelector: {
+ Type: schema.TypeList,
+ Description: "pod selector",
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ FieldPodSelectorNamespace: {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ FieldPodSelectorKind: {
+ Type: schema.TypeString,
+ Optional: true,
+ },
+ FieldMatchLabels: {
+ Type: schema.TypeMap,
+ Optional: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ FieldMatchExpressions: {
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ FieldMatchExpressionKey: {Type: schema.TypeString, Required: true},
+ FieldMatchExpressionOp: {Type: schema.TypeString, Required: true},
+ FieldMatchExpressionVal: {
+ Type: schema.TypeList,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Optional: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ FieldNodeSelector: {
+ Type: schema.TypeList,
+ Description: "node selector",
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ FieldMatchLabels: {
+ Type: schema.TypeMap,
+ Optional: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ },
+ FieldMatchExpressions: {
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ FieldMatchExpressionKey: {Type: schema.TypeString, Required: true},
+ FieldMatchExpressionOp: {Type: schema.TypeString, Required: true},
+ FieldMatchExpressionVal: {
+ Type: schema.TypeList,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Optional: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ FieldEvictionOptionDisabled: {
+ Type: schema.TypeBool,
+ Optional: true,
+ },
+ FieldEvictionOptionAggressive: {
+ Type: schema.TypeBool,
+ Optional: true,
+ },
+ FieldEvictionOptionDisposable: {
+ Type: schema.TypeBool,
+ Optional: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func resourceEvictionConfigRead(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ err := readAdvancedEvictorConfig(ctx, data, meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ return nil
+}
+
+func readAdvancedEvictorConfig(ctx context.Context, data *schema.ResourceData, meta interface{}) error {
+ clusterId := getClusterId(data)
+ if clusterId == "" {
+ log.Print("[INFO] ClusterId is missing. Will skip operation.")
+ return nil
+ }
+ client := meta.(*ProviderConfig).api
+
+ resp, err := client.EvictorAPIGetAdvancedConfigWithResponse(ctx, clusterId)
+ if err != nil {
+ log.Printf("[ERROR] Failed to set read evictor advanced config: %v", err)
+ return err
+ }
+ err = data.Set(FieldEvictorAdvancedConfig, flattenEvictionConfig(resp.JSON200.EvictionConfig))
+ if err != nil {
+ log.Printf("[ERROR] Failed to set field: %v", err)
+ return err
+ }
+
+ return nil
+}
+
+func resourceEvictionConfigCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ if err := upsertEvictionConfigs(ctx, data, meta); err != nil {
+ return diag.FromErr(err)
+ }
+
+ data.SetId(getClusterId(data))
+ return nil
+}
+
+func getEvictorAdvancedConfigAsJson(data *schema.ResourceData) ([]byte, error) {
+ eac, ok := data.GetOk(FieldEvictorAdvancedConfig)
+ if !ok {
+ return nil, fmt.Errorf("failed to extract evictor advanced config [%v], [%+v]", eac, data.GetRawState())
+ }
+
+ evictionConfigs, err := toEvictionConfig(eac)
+ if err != nil {
+ return nil, err
+ }
+ ccd := sdk.CastaiEvictorV1AdvancedConfig{EvictionConfig: evictionConfigs}
+ return json.Marshal(ccd)
+}
+
+func upsertEvictionConfigs(ctx context.Context, data *schema.ResourceData, meta interface{}) error {
+ clusterId := getClusterId(data)
+ if clusterId == "" {
+ log.Print("[INFO] ClusterId is missing. Will skip operation.")
+ return nil
+ }
+ evictorAdvancedConfigJson, err := getEvictorAdvancedConfigAsJson(data)
+ if err != nil {
+ log.Printf("[ERROR] Failed to extract evictor advanced config: %v", err)
+ return err
+ }
+ client := meta.(*ProviderConfig).api
+ resp, err := client.EvictorAPIUpsertAdvancedConfigWithBodyWithResponse(
+ ctx,
+ clusterId,
+ "application/json",
+ bytes.NewReader(evictorAdvancedConfigJson),
+ )
+ if err != nil || resp.JSON200 == nil {
+ log.Printf("[ERROR] Failed to upsert evictor advanced config: %v", err)
+ return err
+ }
+ err = data.Set(FieldEvictorAdvancedConfig, flattenEvictionConfig(resp.JSON200.EvictionConfig))
+ if err != nil {
+ log.Printf("[ERROR] Failed to set field: %v", err)
+ return err
+ }
+
+ return nil
+}
+
+func resourceEvictionConfigUpdate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ err := upsertEvictionConfigs(ctx, data, meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ data.SetId(getClusterId(data))
+ return nil
+}
+
+func resourceEvictionConfigDelete(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ err := deleteEvictionConfigs(ctx, data, meta)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ data.SetId(getClusterId(data))
+ return nil
+}
+
+func deleteEvictionConfigs(ctx context.Context, data *schema.ResourceData, meta interface{}) error {
+
+ clusterId := getClusterId(data)
+ if clusterId == "" {
+ log.Print("[INFO] ClusterId is missing. Will skip operation.")
+ return nil
+ }
+ client := meta.(*ProviderConfig).api
+ resp, err := client.EvictorAPIUpsertAdvancedConfigWithBodyWithResponse(
+ ctx,
+ clusterId,
+ "application/json",
+ bytes.NewReader([]byte("{}")),
+ )
+ if err != nil || resp.JSON200 == nil {
+ log.Printf("[ERROR] Failed to upsert evictor advanced config: %v", err)
+ return err
+ }
+ err = data.Set(FieldEvictorAdvancedConfig, flattenEvictionConfig(resp.JSON200.EvictionConfig))
+ if err != nil {
+ log.Printf("[ERROR] Failed to set field: %v", err)
+ return err
+ }
+
+ return nil
+}
+
+func toEvictionConfig(ii interface{}) ([]sdk.CastaiEvictorV1EvictionConfig, error) {
+ in, ok := ii.([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("expecting []interface, got %T", ii)
+ }
+ if len(in) < 1 {
+ return nil, nil
+ }
+ out := make([]sdk.CastaiEvictorV1EvictionConfig, len(in))
+ var err error
+ for i, c := range in {
+
+ ec := sdk.CastaiEvictorV1EvictionConfig{}
+ cc, ok := c.(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("mapping evictionConfig expecting map[string]interface, got %T, %+v", c, c)
+ }
+
+ for k, v := range cc {
+
+ switch k {
+ case FieldPodSelector:
+ ec.PodSelector, err = toPodSelector(v)
+ if err != nil {
+ return nil, err
+ }
+ case FieldNodeSelector:
+ ec.NodeSelector, err = toNodeSelector(v)
+ if err != nil {
+ return nil, err
+ }
+ case FieldEvictionOptionAggressive:
+ enabled, ok := v.(bool)
+ if !ok {
+ return nil, fmt.Errorf("mapping eviction aggressive expecing bool, got %T, %+v", v, v)
+ }
+ if enabled {
+ ec.Settings.Aggressive = &sdk.CastaiEvictorV1EvictionSettingsSettingEnabled{Enabled: enabled}
+
+ }
+ case FieldEvictionOptionDisabled:
+ enabled, ok := v.(bool)
+ if !ok {
+ return nil, fmt.Errorf("mapping eviction disabled expecing bool, got %T, %+v", v, v)
+ }
+ if enabled {
+ ec.Settings.RemovalDisabled = &sdk.CastaiEvictorV1EvictionSettingsSettingEnabled{Enabled: enabled}
+ }
+ case FieldEvictionOptionDisposable:
+ enabled, ok := v.(bool)
+ if !ok {
+ return nil, fmt.Errorf("mapping eviction aggressive expecing bool, got %T, %+v", v, v)
+ }
+ if enabled {
+ ec.Settings.Disposable = &sdk.CastaiEvictorV1EvictionSettingsSettingEnabled{Enabled: enabled}
+ }
+ default:
+ return nil, fmt.Errorf("unexpected field %s, %T, %+v", k, v, v)
+ }
+ }
+ out[i] = ec
+ }
+ return out, nil
+}
+func flattenEvictionConfig(ecs []sdk.CastaiEvictorV1EvictionConfig) []map[string]any {
+ if ecs == nil {
+ return nil
+ }
+ res := make([]map[string]any, len(ecs))
+ for i, c := range ecs {
+ out := map[string]any{}
+ if c.PodSelector != nil {
+ out[FieldPodSelector] = flattenPodSelector(c.PodSelector)
+ }
+ if c.NodeSelector != nil {
+ out[FieldNodeSelector] = flattenNodeSelector(c.NodeSelector)
+ }
+ if c.Settings.Aggressive != nil {
+ out[FieldEvictionOptionAggressive] = c.Settings.Aggressive.Enabled
+ }
+
+ if c.Settings.Disposable != nil {
+ out[FieldEvictionOptionDisposable] = c.Settings.Disposable.Enabled
+ }
+
+ if c.Settings.RemovalDisabled != nil {
+ out[FieldEvictionOptionDisabled] = c.Settings.RemovalDisabled.Enabled
+ }
+ res[i] = out
+ }
+
+ return res
+}
+
+func toPodSelector(in interface{}) (*sdk.CastaiEvictorV1PodSelector, error) {
+ iii, ok := in.([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("mapping podselector expecting []interface, got %T, %+v", in, in)
+ }
+ if len(iii) < 1 {
+ return nil, nil
+ }
+ ii := iii[0].(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("mapping podselector expecting map[string]interface, got %T, %+v", in, in)
+ }
+ out := sdk.CastaiEvictorV1PodSelector{}
+ for k, v := range ii {
+ switch k {
+ case FieldPodSelectorKind:
+ if kind, ok := v.(string); ok {
+ out.Kind = lo.ToPtr(kind)
+ } else {
+ return nil, fmt.Errorf("expecting bool, got %T", v)
+ }
+ case FieldPodSelectorNamespace:
+ if namespace, ok := v.(string); ok {
+ if len(namespace) == 0 {
+ continue
+ }
+ out.Namespace = lo.ToPtr(namespace)
+ } else {
+ return nil, fmt.Errorf("expecting bool, got %T", v)
+ }
+ case FieldMatchExpressions:
+ if mes, ok := v.([]interface{}); ok {
+ me, err := toMatchExpressions(mes)
+ if err != nil {
+ return nil, err
+ }
+ if len(me) < 1 {
+ continue
+ }
+ out.LabelSelector.MatchExpressions = &me
+ } else {
+ return nil, fmt.Errorf("mapping match_expressions expecting map[string]interface, got %T, %+v", v, v)
+ }
+ case FieldMatchLabels:
+ mls, err := toMatchLabels(v)
+ if err != nil {
+ return nil, err
+ }
+
+ out.LabelSelector.MatchLabels = mls
+ }
+ }
+ return &out, nil
+}
+
+func toNodeSelector(in interface{}) (*sdk.CastaiEvictorV1NodeSelector, error) {
+ iii, ok := in.([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("mapping nodeselector expecting []interface, got %T, %+v", in, in)
+ }
+ if len(iii) < 1 {
+ return nil, nil
+ }
+ ii := iii[0].(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("mapping podselector expecting map[string]interface, got %T, %+v", in, in)
+ }
+ out := sdk.CastaiEvictorV1NodeSelector{}
+ for k, v := range ii {
+ switch k {
+
+ case FieldMatchExpressions:
+ if mes, ok := v.([]interface{}); ok {
+ me, err := toMatchExpressions(mes)
+ if err != nil {
+ return nil, err
+ }
+ out.LabelSelector.MatchExpressions = &me
+ } else {
+ return nil, fmt.Errorf("mapping match_expressions expecting map[string]interface, got %T, %+v", v, v)
+ }
+ case FieldMatchLabels:
+ mls, err := toMatchLabels(v)
+ if err != nil {
+ return nil, err
+ }
+ out.LabelSelector.MatchLabels = mls
+ }
+ }
+ return &out, nil
+}
+
+func toMatchLabels(in interface{}) (*sdk.CastaiEvictorV1LabelSelector_MatchLabels, error) {
+ mls, ok := in.(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("mapping match_labels expecting map[string]interface, got %T %+v", in, in)
+ }
+ if len(mls) == 0 {
+ return nil, nil
+ }
+ out := sdk.CastaiEvictorV1LabelSelector_MatchLabels{AdditionalProperties: map[string]string{}}
+ for k, v := range mls {
+ value, ok := v.(string)
+ if !ok {
+ return nil, fmt.Errorf("mapping match_labels expecting string, got %T %+v", v, v)
+ }
+ out.AdditionalProperties[k] = value
+ }
+
+ return &out, nil
+}
+
+func flattenPodSelector(ps *sdk.CastaiEvictorV1PodSelector) []map[string]any {
+ if ps == nil {
+ return nil
+ }
+ out := map[string]any{}
+ if ps.Kind != nil {
+ out[FieldPodSelectorKind] = *ps.Kind
+ }
+ if ps.Namespace != nil {
+ out[FieldPodSelectorNamespace] = *ps.Namespace
+ }
+ if ps.LabelSelector.MatchLabels != nil {
+ out[FieldMatchLabels] = ps.LabelSelector.MatchLabels.AdditionalProperties
+ }
+ if ps.LabelSelector.MatchExpressions != nil {
+ out[FieldMatchExpressions] = flattenMatchExpressions(*ps.LabelSelector.MatchExpressions)
+ }
+ return []map[string]any{out}
+}
+
+func flattenNodeSelector(ns *sdk.CastaiEvictorV1NodeSelector) []map[string]any {
+ if ns == nil {
+ return nil
+ }
+ out := map[string]any{}
+ if ns.LabelSelector.MatchLabels != nil {
+ out[FieldMatchLabels] = ns.LabelSelector.MatchLabels.AdditionalProperties
+ }
+ if ns.LabelSelector.MatchExpressions != nil {
+ out[FieldMatchExpressions] = flattenMatchExpressions(*ns.LabelSelector.MatchExpressions)
+ }
+
+ return []map[string]any{out}
+}
+
+func flattenMatchExpressions(mes []sdk.CastaiEvictorV1LabelSelectorExpression) []map[string]any {
+ if mes == nil {
+ return nil
+ }
+
+ out := make([]map[string]any, len(mes))
+ for i, me := range mes {
+ out[i] = map[string]any{
+ FieldMatchExpressionKey: me.Key,
+ FieldMatchExpressionOp: string(me.Operator),
+ }
+ if me.Values != nil && len(*me.Values) > 0 {
+ out[i][FieldMatchExpressionVal] = *me.Values
+ }
+ }
+
+ return out
+}
+
+func toMatchExpressions(in []interface{}) ([]sdk.CastaiEvictorV1LabelSelectorExpression, error) {
+ out := make([]sdk.CastaiEvictorV1LabelSelectorExpression, len(in))
+ for i, mei := range in {
+ if me, ok := mei.(map[string]interface{}); ok {
+ out[i] = sdk.CastaiEvictorV1LabelSelectorExpression{}
+ for k, v := range me {
+ switch k {
+ case FieldMatchExpressionKey:
+ if key, ok := v.(string); ok {
+ out[i].Key = key
+ } else {
+ return nil, fmt.Errorf("mapping match_expression key expecting string, got %T %+v", v, v)
+ }
+ case FieldMatchExpressionOp:
+ if op, ok := v.(string); ok {
+ out[i].Operator = sdk.CastaiEvictorV1LabelSelectorExpressionOperator(op)
+ } else {
+ return nil, fmt.Errorf("mapping match_expression operator expecting string, got %T %+v", v, v)
+ }
+ case FieldMatchExpressionVal:
+ if vals, ok := v.([]interface{}); ok {
+ outVals := make([]string, len(vals))
+ for vi, vv := range vals {
+ outVals[vi], ok = vv.(string)
+ if !ok {
+ return nil, fmt.Errorf("mapping match_expression values expecting string, got %T %+v", vv, vv)
+ }
+ }
+ out[i].Values = &outVals
+ } else {
+ return nil, fmt.Errorf("mapping match_expression values expecting []interface{}, got %T %+v", v, v)
+ }
+
+ }
+
+ }
+ } else {
+ return nil, fmt.Errorf("mapping match_expressions expecting map[string]interface, got %T, %+v", mei, mei)
+ }
+
+ }
+ return out, nil
+}
diff --git a/castai/resource_eviction_config_test.go b/castai/resource_eviction_config_test.go
new file mode 100644
index 00000000..2590eb18
--- /dev/null
+++ b/castai/resource_eviction_config_test.go
@@ -0,0 +1,410 @@
+package castai
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "github.com/castai/terraform-provider-castai/castai/sdk"
+ mock_sdk "github.com/castai/terraform-provider-castai/castai/sdk/mock"
+ "github.com/golang/mock/gomock"
+ "github.com/hashicorp/go-cty/cty"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+ "github.com/samber/lo"
+ "github.com/stretchr/testify/require"
+ "io"
+ "net/http"
+ "testing"
+)
+
+func TestEvictionConfig_ReadContext(t *testing.T) {
+
+ mockctrl := gomock.NewController(t)
+ mockClient := mock_sdk.NewMockClientInterface(mockctrl)
+
+ ctx := context.Background()
+ provider := &ProviderConfig{
+ api: &sdk.ClientWithResponses{
+ ClientInterface: mockClient,
+ },
+ }
+ clusterId := "b6bfc074-a267-400f-b8f1-db0850c369b1"
+
+ resource := resourceEvictionConfig()
+ val := cty.ObjectVal(map[string]cty.Value{
+ FieldClusterId: cty.StringVal(clusterId),
+ })
+ initialState := terraform.NewInstanceStateShimmedFromValue(val, 0)
+
+ tests := map[string]struct {
+ data string
+ testFunc func(*testing.T, diag.Diagnostics, *schema.ResourceData)
+ }{
+ "should work with empty config": {
+ data: `{"evictionConfig":[]}`,
+ testFunc: func(t *testing.T, res diag.Diagnostics, data *schema.ResourceData) {
+ r := require.New(t)
+ r.Nil(res)
+ r.False(res.HasError())
+ eac, isOK := data.GetOk(FieldEvictorAdvancedConfig)
+ r.False(isOK)
+ fmt.Printf("is not %T, %+v", eac, eac)
+ d, ok := eac.([]interface{})
+ r.True(ok)
+ r.Len(d, 0)
+
+ },
+ },
+ "should read config": {
+ data: `{"evictionConfig":[{"podSelector":{"kind":"Job","labelSelector":{"matchLabels":{"key1":"value1"}}},"settings":{"aggressive":{"enabled":true}}}]}`,
+ testFunc: func(t *testing.T, res diag.Diagnostics, data *schema.ResourceData) {
+ r := require.New(t)
+ r.Nil(res)
+ r.False(res.HasError())
+ eac, isOK := data.GetOk(FieldEvictorAdvancedConfig)
+ r.True(isOK)
+ r.NotNil(eac)
+ podSelectorKind, isOK := data.GetOk(fmt.Sprintf("%s.0.%s.0.kind", FieldEvictorAdvancedConfig, FieldPodSelector))
+ r.True(isOK)
+ r.NotNil(podSelectorKind)
+ r.Equal("Job", podSelectorKind)
+ podSelectorLabelValue, isOK := data.GetOk(fmt.Sprintf("%s.0.%s.0.%s.key1", FieldEvictorAdvancedConfig, FieldPodSelector, FieldMatchLabels))
+ r.True(isOK)
+ r.NotNil(podSelectorLabelValue)
+ r.Equal("value1", podSelectorLabelValue)
+ },
+ },
+ "should handle multiple evictionConfig objects": {
+ data: `{"evictionConfig":[
+ {"podSelector":{"kind":"Job","labelSelector":{"matchLabels":{"key1":"value1"}}},"settings":{"aggressive":{"enabled":true}}},
+ {"nodeSelector":{"labelSelector":{"matchLabels":{"node-label":"value1"}}},"settings":{"disposable":{"enabled":true}}}]}`,
+ testFunc: func(t *testing.T, res diag.Diagnostics, data *schema.ResourceData) {
+ r := require.New(t)
+ r.Nil(res)
+ r.False(res.HasError())
+ eac, isOK := data.GetOk(FieldEvictorAdvancedConfig)
+ r.True(isOK)
+ r.NotNil(eac)
+ podSelectorKind, isOK := data.GetOk(fmt.Sprintf("%s.0.%s.0.kind", FieldEvictorAdvancedConfig, FieldPodSelector))
+ r.True(isOK)
+ r.NotNil(podSelectorKind)
+ r.Equal("Job", podSelectorKind)
+ podSelectorLabelValue, isOK := data.GetOk(fmt.Sprintf("%s.0.%s.0.%s.key1", FieldEvictorAdvancedConfig, FieldPodSelector, FieldMatchLabels))
+ r.True(isOK)
+ r.NotNil(podSelectorLabelValue)
+ r.Equal("value1", podSelectorLabelValue)
+ nodeSelectorLabelValue, isOK := data.GetOk(fmt.Sprintf("%s.1.%s.0.%s.node-label", FieldEvictorAdvancedConfig, FieldNodeSelector, FieldMatchLabels))
+ r.True(isOK)
+ r.NotNil(nodeSelectorLabelValue)
+ r.Equal("value1", nodeSelectorLabelValue)
+ },
+ },
+ "should handle label expressions": {
+ data: `{"evictionConfig":[ {"podSelector":{"kind":"Job","labelSelector":{"matchExpressions":[{"key":"value1", "operator":"In", "values":["v1", "v2"]}]}},"settings":{"aggressive":{"enabled":true}}} ]}`,
+ testFunc: func(t *testing.T, res diag.Diagnostics, data *schema.ResourceData) {
+ r := require.New(t)
+ r.Nil(res)
+ r.False(res.HasError())
+ eac, isOK := data.GetOk(FieldEvictorAdvancedConfig)
+ r.True(isOK)
+ r.NotNil(eac)
+ podSelectorKeyValue, isOK := data.GetOk(fmt.Sprintf("%s.0.%s.0.%s.0.key", FieldEvictorAdvancedConfig, FieldPodSelector, FieldMatchExpressions))
+ r.True(isOK)
+ r.NotNil(podSelectorKeyValue)
+ r.Equal("value1", podSelectorKeyValue)
+ podSelectorValues, isOK := data.GetOk(fmt.Sprintf("%s.0.%s.0.%s.0.values", FieldEvictorAdvancedConfig, FieldPodSelector, FieldMatchExpressions))
+ r.True(isOK)
+ r.NotNil(podSelectorValues)
+ r.Equal([]interface{}{"v1", "v2"}, podSelectorValues)
+ },
+ },
+ }
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ body := io.NopCloser(bytes.NewReader([]byte(test.data)))
+
+ mockClient.EXPECT().
+ EvictorAPIGetAdvancedConfig(gomock.Any(), clusterId).
+ Return(&http.Response{StatusCode: 200, Body: body, Header: map[string][]string{"Content-Type": {"json"}}}, nil)
+ data := resource.Data(initialState)
+
+ result := resource.ReadContext(ctx, data, provider)
+ test.testFunc(t, result, data)
+
+ })
+ }
+
+}
+
+func TestEvictionConfig_CreateContext(t *testing.T) {
+ r := require.New(t)
+ mockctrl := gomock.NewController(t)
+ mockClient := mock_sdk.NewMockClientInterface(mockctrl)
+
+ ctx := context.Background()
+ provider := &ProviderConfig{
+ api: &sdk.ClientWithResponses{
+ ClientInterface: mockClient,
+ },
+ }
+ clusterId := "b6bfc074-a267-400f-b8f1-db0850c369b1"
+ evictionConfigResponse := `{
+ "evictionConfig": [
+ {
+ "podSelector": {
+ "kind": "Job",
+ "labelSelector": {
+ "matchLabels": {
+ "key1": "value1"
+ }
+ }
+ },
+ "settings": {
+ "aggressive": {
+ "enabled": true
+ }
+ }
+ }
+ ]
+}`
+
+ resource := resourceEvictionConfig()
+
+ val := cty.ObjectVal(map[string]cty.Value{
+ FieldClusterId: cty.StringVal(clusterId),
+ FieldEvictorAdvancedConfig: cty.ListVal([]cty.Value{
+ cty.ObjectVal(map[string]cty.Value{
+ "pod_selector": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+ "kind": cty.StringVal("Job"),
+ "match_labels": cty.MapVal(map[string]cty.Value{
+ "key1": cty.StringVal("value1"),
+ }),
+ }),
+ }),
+ "aggressive": cty.BoolVal(true),
+ }),
+ }),
+ })
+
+ state := terraform.NewInstanceStateShimmedFromValue(val, 0)
+ data := resource.Data(state)
+
+ mockClient.EXPECT().EvictorAPIUpsertAdvancedConfigWithBody(gomock.Any(), clusterId, "application/json", gomock.Any()).
+ DoAndReturn(func(ctx context.Context, clusterId string, contentType string, body io.Reader) (*http.Response, error) {
+
+ got, _ := io.ReadAll(body)
+ expected := []byte(evictionConfigResponse)
+
+ eq, err := JSONBytesEqual(got, expected)
+ r.NoError(err)
+ r.True(eq, fmt.Sprintf("got: %v\n"+
+ "expected: %v\n", string(got), string(expected)))
+
+ return &http.Response{
+ StatusCode: 200,
+ Header: map[string][]string{"Content-Type": {"json"}},
+ Body: io.NopCloser(bytes.NewReader([]byte(evictionConfigResponse))),
+ }, nil
+ }).Times(1)
+
+ result := resource.CreateContext(ctx, data, provider)
+
+ r.Nil(result)
+ r.False(result.HasError())
+ eac, isOK := data.GetOk(FieldEvictorAdvancedConfig)
+ r.True(isOK)
+ r.NotNil(eac)
+ podSelectorKind, isOK := data.GetOk(fmt.Sprintf("%s.0.%s.0.kind", FieldEvictorAdvancedConfig, FieldPodSelector))
+ r.True(isOK)
+ r.NotNil(podSelectorKind)
+ r.Equal("Job", podSelectorKind)
+}
+
+func TestEvictionConfig_UpdateContext(t *testing.T) {
+ r := require.New(t)
+ mockctrl := gomock.NewController(t)
+ mockClient := mock_sdk.NewMockClientInterface(mockctrl)
+
+ ctx := context.Background()
+ provider := &ProviderConfig{
+ api: &sdk.ClientWithResponses{
+ ClientInterface: mockClient,
+ },
+ }
+ clusterId := "b6bfc074-a267-400f-b8f1-db0850c369b1"
+ initialConfigJson := `
+ {
+ "evictionConfig": [
+ {
+ "podSelector": {
+ "kind": "Job",
+ "labelSelector": {
+ "matchLabels": {
+ "key1": "value1"
+ }
+ }
+ },
+ "settings": {
+ "aggressive": {
+ "enabled": true
+ }
+ }
+ }
+ ]
+}`
+ evictionConfigJson := `
+ {
+ "evictionConfig": [
+ {
+ "podSelector": {
+ "kind": "Job",
+ "labelSelector": {
+ "matchLabels": {
+ "key1": "value1"
+ }
+ }
+ },
+ "settings": {
+ "aggressive": {
+ "enabled": true
+ }
+ }
+ },
+ {
+ "nodeSelector": {
+ "labelSelector": {
+ "matchExpressions": [
+ {
+ "key": "key1",
+ "operator": "In",
+ "values": [
+ "val1",
+ "val2"
+ ]
+ }
+ ]}
+ },
+ "settings": {
+ "disposable": {
+ "enabled": true
+ }
+ }
+ }
+ ]
+}`
+
+ initialConfig := sdk.CastaiEvictorV1EvictionConfig{
+ Settings: sdk.CastaiEvictorV1EvictionSettings{Aggressive: &sdk.CastaiEvictorV1EvictionSettingsSettingEnabled{Enabled: true}},
+ PodSelector: &sdk.CastaiEvictorV1PodSelector{
+ Kind: lo.ToPtr("Job"),
+ LabelSelector: sdk.CastaiEvictorV1LabelSelector{
+ MatchLabels: &sdk.CastaiEvictorV1LabelSelector_MatchLabels{AdditionalProperties: map[string]string{
+ "key1": "value1",
+ }}}}}
+
+ newConfig := sdk.CastaiEvictorV1EvictionConfig{
+ Settings: sdk.CastaiEvictorV1EvictionSettings{Disposable: &sdk.CastaiEvictorV1EvictionSettingsSettingEnabled{Enabled: true}},
+ NodeSelector: &sdk.CastaiEvictorV1NodeSelector{
+ LabelSelector: sdk.CastaiEvictorV1LabelSelector{MatchExpressions: &[]sdk.CastaiEvictorV1LabelSelectorExpression{{
+ Key: "key1",
+ Operator: "In",
+ Values: &[]string{"val1", "val2"},
+ }}}}}
+ finalConfiuration := []sdk.CastaiEvictorV1EvictionConfig{initialConfig, newConfig}
+ resource := resourceEvictionConfig()
+
+ val := cty.ObjectVal(map[string]cty.Value{
+ FieldClusterId: cty.StringVal(clusterId),
+ })
+
+ state := terraform.NewInstanceStateShimmedFromValue(val, 0)
+ data := resource.Data(state)
+
+ body := io.NopCloser(bytes.NewReader([]byte(initialConfigJson)))
+ mockClient.EXPECT().
+ EvictorAPIGetAdvancedConfig(gomock.Any(), clusterId).
+ Return(&http.Response{StatusCode: 200, Body: body, Header: map[string][]string{"Content-Type": {"json"}}}, nil)
+
+ result := resource.ReadContext(ctx, data, provider)
+ r.Nil(result)
+ r.False(result.HasError())
+
+ mockClient.EXPECT().EvictorAPIUpsertAdvancedConfigWithBody(gomock.Any(), clusterId, "application/json", gomock.Any()).
+ DoAndReturn(func(ctx context.Context, clusterId string, contentType string, body io.Reader) (*http.Response, error) {
+ got, _ := io.ReadAll(body)
+ expected := []byte(evictionConfigJson)
+
+ eq, err := JSONBytesEqual(got, expected)
+ r.NoError(err)
+ r.True(eq, fmt.Sprintf("got: %v\n"+
+ "expected: %v\n", string(got), string(expected)))
+
+ return &http.Response{
+ StatusCode: 200,
+ Header: map[string][]string{"Content-Type": {"json"}},
+ Body: io.NopCloser(bytes.NewReader([]byte(evictionConfigJson))),
+ }, nil
+ }).Times(1)
+ err := data.Set(FieldEvictorAdvancedConfig, flattenEvictionConfig(finalConfiuration))
+ r.NoError(err)
+ updateResult := resource.UpdateContext(ctx, data, provider)
+
+ r.Nil(updateResult)
+ r.False(result.HasError())
+ eac, isOK := data.GetOk(FieldEvictorAdvancedConfig)
+ r.True(isOK)
+ r.NotNil(eac)
+}
+
+func TestEvictionConfig_DeleteContext(t *testing.T) {
+ r := require.New(t)
+ mockctrl := gomock.NewController(t)
+ mockClient := mock_sdk.NewMockClientInterface(mockctrl)
+
+ ctx := context.Background()
+ provider := &ProviderConfig{
+ api: &sdk.ClientWithResponses{
+ ClientInterface: mockClient,
+ },
+ }
+ clusterId := "b6bfc074-a267-400f-b8f1-db0850c369b1"
+ evictionConfigJson := `{"evictionConfig": []}`
+
+ resource := resourceEvictionConfig()
+
+ val := cty.ObjectVal(map[string]cty.Value{
+ FieldClusterId: cty.StringVal(clusterId),
+ FieldEvictorAdvancedConfig: cty.ListVal([]cty.Value{
+ cty.ObjectVal(map[string]cty.Value{
+ "pod_selector": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
+ "match_labels": cty.MapVal(map[string]cty.Value{
+ "key1": cty.StringVal("val1"),
+ }),
+ }),
+ }),
+ "aggressive": cty.BoolVal(true),
+ }),
+ }),
+ })
+
+ state := terraform.NewInstanceStateShimmedFromValue(val, 0)
+ data := resource.Data(state)
+
+ mockClient.EXPECT().EvictorAPIUpsertAdvancedConfigWithBody(gomock.Any(), clusterId, "application/json", gomock.Any()).
+ DoAndReturn(func(ctx context.Context, clusterId string, contentType string, body io.Reader) (*http.Response, error) {
+ return &http.Response{
+ StatusCode: 200,
+ Header: map[string][]string{"Content-Type": {"json"}},
+ Body: io.NopCloser(bytes.NewReader([]byte(evictionConfigJson))),
+ }, nil
+ }).Times(1)
+
+ result := resource.DeleteContext(ctx, data, provider)
+
+ r.Nil(result)
+ r.False(result.HasError())
+ eac, isOK := data.GetOk(FieldEvictorAdvancedConfig)
+ r.False(isOK)
+ r.Equal([]interface{}{}, eac)
+}
diff --git a/castai/sdk/api.gen.go b/castai/sdk/api.gen.go
index eddba1f3..421eeaea 100644
--- a/castai/sdk/api.gen.go
+++ b/castai/sdk/api.gen.go
@@ -23,6 +23,15 @@ const (
Viewer OrganizationRole = "viewer"
)
+// Defines values for CastaiEvictorV1LabelSelectorExpressionOperator.
+const (
+ CastaiEvictorV1LabelSelectorExpressionOperatorDoesNotExist CastaiEvictorV1LabelSelectorExpressionOperator = "DoesNotExist"
+ CastaiEvictorV1LabelSelectorExpressionOperatorExists CastaiEvictorV1LabelSelectorExpressionOperator = "Exists"
+ CastaiEvictorV1LabelSelectorExpressionOperatorIn CastaiEvictorV1LabelSelectorExpressionOperator = "In"
+ CastaiEvictorV1LabelSelectorExpressionOperatorInvalid CastaiEvictorV1LabelSelectorExpressionOperator = "Invalid"
+ CastaiEvictorV1LabelSelectorExpressionOperatorNotIn CastaiEvictorV1LabelSelectorExpressionOperator = "NotIn"
+)
+
// Defines values for CastaiInventoryV1beta1AttachableGPUDeviceManufacturer.
const (
CastaiInventoryV1beta1AttachableGPUDeviceManufacturerAMD CastaiInventoryV1beta1AttachableGPUDeviceManufacturer = "AMD"
@@ -53,14 +62,14 @@ const (
// Defines values for CastaiV1Cloud.
const (
- AWS CastaiV1Cloud = "AWS"
- AZURE CastaiV1Cloud = "AZURE"
- Aws CastaiV1Cloud = "aws"
- Azure CastaiV1Cloud = "azure"
- GCP CastaiV1Cloud = "GCP"
- Gcp CastaiV1Cloud = "gcp"
- INVALID CastaiV1Cloud = "INVALID"
- Invalid CastaiV1Cloud = "invalid"
+ CastaiV1CloudAWS CastaiV1Cloud = "AWS"
+ CastaiV1CloudAZURE CastaiV1Cloud = "AZURE"
+ CastaiV1CloudAws CastaiV1Cloud = "aws"
+ CastaiV1CloudAzure CastaiV1Cloud = "azure"
+ CastaiV1CloudGCP CastaiV1Cloud = "GCP"
+ CastaiV1CloudGcp CastaiV1Cloud = "gcp"
+ CastaiV1CloudINVALID CastaiV1Cloud = "INVALID"
+ CastaiV1CloudInvalid CastaiV1Cloud = "invalid"
)
// Defines values for ExternalclusterV1NodeType.
@@ -261,6 +270,78 @@ type CastaiAuthtokenV1beta1ListAuthTokensResponse struct {
Items *[]CastaiAuthtokenV1beta1AuthToken `json:"items,omitempty"`
}
+// AdvancedConfig the evictor advanced configuration.
+type CastaiEvictorV1AdvancedConfig struct {
+ EvictionConfig []CastaiEvictorV1EvictionConfig `json:"evictionConfig"`
+}
+
+// EvictionConfig used to specify more granular settings per node/pod filters.
+type CastaiEvictorV1EvictionConfig struct {
+ NodeSelector *CastaiEvictorV1NodeSelector `json:"nodeSelector,omitempty"`
+ PodSelector *CastaiEvictorV1PodSelector `json:"podSelector,omitempty"`
+ Settings CastaiEvictorV1EvictionSettings `json:"settings"`
+}
+
+// CastaiEvictorV1EvictionSettings defines model for castai.evictor.v1.EvictionSettings.
+type CastaiEvictorV1EvictionSettings struct {
+ Aggressive *CastaiEvictorV1EvictionSettingsSettingEnabled `json:"aggressive,omitempty"`
+ Disposable *CastaiEvictorV1EvictionSettingsSettingEnabled `json:"disposable,omitempty"`
+ RemovalDisabled *CastaiEvictorV1EvictionSettingsSettingEnabled `json:"removalDisabled,omitempty"`
+}
+
+// CastaiEvictorV1EvictionSettingsSettingEnabled defines model for castai.evictor.v1.EvictionSettings.SettingEnabled.
+type CastaiEvictorV1EvictionSettingsSettingEnabled struct {
+ Enabled bool `json:"enabled"`
+}
+
+// LabelSelector is a proto mirror of the metav1.LabelSelector K8s API object. Properties `match_labels` and
+// `match_expressions` are ANDed.
+type CastaiEvictorV1LabelSelector struct {
+ // A more advanced label query with operators. Multiple expressions are ANDed.
+ MatchExpressions *[]CastaiEvictorV1LabelSelectorExpression `json:"matchExpressions,omitempty"`
+
+ // Used to query resource labels.
+ MatchLabels *CastaiEvictorV1LabelSelector_MatchLabels `json:"matchLabels,omitempty"`
+}
+
+// Used to query resource labels.
+type CastaiEvictorV1LabelSelector_MatchLabels struct {
+ AdditionalProperties map[string]string `json:"-"`
+}
+
+// Expression is a proto mirror of the metav1.LabelSelectorRequirement K8s API object.
+type CastaiEvictorV1LabelSelectorExpression struct {
+ // Key is a label.
+ Key string `json:"key"`
+
+ // Operator set of operators which can be used in the label selector expressions.
+ Operator CastaiEvictorV1LabelSelectorExpressionOperator `json:"operator"`
+
+ // Values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the
+ // operator is Exists or DoesNotExist, the values array must be empty.
+ Values *[]string `json:"values,omitempty"`
+}
+
+// Operator set of operators which can be used in the label selector expressions.
+type CastaiEvictorV1LabelSelectorExpressionOperator string
+
+// CastaiEvictorV1NodeSelector defines model for castai.evictor.v1.NodeSelector.
+type CastaiEvictorV1NodeSelector struct {
+ // LabelSelector is a proto mirror of the metav1.LabelSelector K8s API object. Properties `match_labels` and
+ // `match_expressions` are ANDed.
+ LabelSelector CastaiEvictorV1LabelSelector `json:"labelSelector"`
+}
+
+// CastaiEvictorV1PodSelector defines model for castai.evictor.v1.PodSelector.
+type CastaiEvictorV1PodSelector struct {
+ Kind *string `json:"kind,omitempty"`
+
+ // LabelSelector is a proto mirror of the metav1.LabelSelector K8s API object. Properties `match_labels` and
+ // `match_expressions` are ANDed.
+ LabelSelector CastaiEvictorV1LabelSelector `json:"labelSelector"`
+ Namespace *string `json:"namespace,omitempty"`
+}
+
// CastaiInventoryV1beta1AddReservationResponse defines model for castai.inventory.v1beta1.AddReservationResponse.
type CastaiInventoryV1beta1AddReservationResponse struct {
Reservation *CastaiInventoryV1beta1ReservationDetails `json:"reservation,omitempty"`
@@ -1564,7 +1645,8 @@ type NodetemplatesV1TemplateConstraints struct {
MinMemory *int32 `json:"minMemory"`
// Should include on-demand instances in the considered pool.
- OnDemand *bool `json:"onDemand"`
+ OnDemand *bool `json:"onDemand"`
+ Os *[]string `json:"os,omitempty"`
// Should include spot instances in the considered pool.
// Note 1: if both spot and on-demand are false, then on-demand is assumed.
@@ -2036,6 +2118,9 @@ type CreateInvitationJSONBody = NewInvitations
// ClaimInvitationJSONBody defines parameters for ClaimInvitation.
type ClaimInvitationJSONBody = map[string]interface{}
+// EvictorAPIUpsertAdvancedConfigJSONBody defines parameters for EvictorAPIUpsertAdvancedConfig.
+type EvictorAPIUpsertAdvancedConfigJSONBody = CastaiEvictorV1AdvancedConfig
+
// NodeTemplatesAPIFilterInstanceTypesJSONBody defines parameters for NodeTemplatesAPIFilterInstanceTypes.
type NodeTemplatesAPIFilterInstanceTypesJSONBody = NodetemplatesV1NodeTemplate
@@ -2172,6 +2257,9 @@ type CreateInvitationJSONRequestBody = CreateInvitationJSONBody
// ClaimInvitationJSONRequestBody defines body for ClaimInvitation for application/json ContentType.
type ClaimInvitationJSONRequestBody = ClaimInvitationJSONBody
+// EvictorAPIUpsertAdvancedConfigJSONRequestBody defines body for EvictorAPIUpsertAdvancedConfig for application/json ContentType.
+type EvictorAPIUpsertAdvancedConfigJSONRequestBody = EvictorAPIUpsertAdvancedConfigJSONBody
+
// NodeTemplatesAPIFilterInstanceTypesJSONRequestBody defines body for NodeTemplatesAPIFilterInstanceTypes for application/json ContentType.
type NodeTemplatesAPIFilterInstanceTypesJSONRequestBody = NodeTemplatesAPIFilterInstanceTypesJSONBody
@@ -2244,6 +2332,59 @@ type ScheduledRebalancingAPICreateRebalancingScheduleJSONRequestBody = Scheduled
// ScheduledRebalancingAPIUpdateRebalancingScheduleJSONRequestBody defines body for ScheduledRebalancingAPIUpdateRebalancingSchedule for application/json ContentType.
type ScheduledRebalancingAPIUpdateRebalancingScheduleJSONRequestBody = ScheduledRebalancingAPIUpdateRebalancingScheduleJSONBody
+// Getter for additional properties for CastaiEvictorV1LabelSelector_MatchLabels. Returns the specified
+// element and whether it was found
+func (a CastaiEvictorV1LabelSelector_MatchLabels) Get(fieldName string) (value string, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for CastaiEvictorV1LabelSelector_MatchLabels
+func (a *CastaiEvictorV1LabelSelector_MatchLabels) Set(fieldName string, value string) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]string)
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for CastaiEvictorV1LabelSelector_MatchLabels to handle AdditionalProperties
+func (a *CastaiEvictorV1LabelSelector_MatchLabels) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]string)
+ for fieldName, fieldBuf := range object {
+ var fieldVal string
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for CastaiEvictorV1LabelSelector_MatchLabels to handle AdditionalProperties
+func (a CastaiEvictorV1LabelSelector_MatchLabels) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
// Getter for additional properties for ExternalclusterV1EKSClusterParams_Tags. Returns the specified
// element and whether it was found
func (a ExternalclusterV1EKSClusterParams_Tags) Get(fieldName string) (value string, found bool) {
diff --git a/castai/sdk/client.gen.go b/castai/sdk/client.gen.go
index 8cec0722..d936d843 100644
--- a/castai/sdk/client.gen.go
+++ b/castai/sdk/client.gen.go
@@ -125,6 +125,14 @@ type ClientInterface interface {
ClaimInvitation(ctx context.Context, id string, body ClaimInvitationJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // EvictorAPIGetAdvancedConfig request
+ EvictorAPIGetAdvancedConfig(ctx context.Context, clusterId string, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // EvictorAPIUpsertAdvancedConfig request with any body
+ EvictorAPIUpsertAdvancedConfigWithBody(ctx context.Context, clusterId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ EvictorAPIUpsertAdvancedConfig(ctx context.Context, clusterId string, body EvictorAPIUpsertAdvancedConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// NodeTemplatesAPIFilterInstanceTypes request with any body
NodeTemplatesAPIFilterInstanceTypesWithBody(ctx context.Context, clusterId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -534,6 +542,42 @@ func (c *Client) ClaimInvitation(ctx context.Context, id string, body ClaimInvit
return c.Client.Do(req)
}
+func (c *Client) EvictorAPIGetAdvancedConfig(ctx context.Context, clusterId string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewEvictorAPIGetAdvancedConfigRequest(c.Server, clusterId)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) EvictorAPIUpsertAdvancedConfigWithBody(ctx context.Context, clusterId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewEvictorAPIUpsertAdvancedConfigRequestWithBody(c.Server, clusterId, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) EvictorAPIUpsertAdvancedConfig(ctx context.Context, clusterId string, body EvictorAPIUpsertAdvancedConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewEvictorAPIUpsertAdvancedConfigRequest(c.Server, clusterId, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) NodeTemplatesAPIFilterInstanceTypesWithBody(ctx context.Context, clusterId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewNodeTemplatesAPIFilterInstanceTypesRequestWithBody(c.Server, clusterId, contentType, body)
if err != nil {
@@ -2024,6 +2068,87 @@ func NewClaimInvitationRequestWithBody(server string, id string, contentType str
return req, nil
}
+// NewEvictorAPIGetAdvancedConfigRequest generates requests for EvictorAPIGetAdvancedConfig
+func NewEvictorAPIGetAdvancedConfigRequest(server string, clusterId string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithLocation("simple", false, "clusterId", runtime.ParamLocationPath, clusterId)
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/v1/kubernetes/clusters/%s/evictor-advanced-config", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("GET", queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewEvictorAPIUpsertAdvancedConfigRequest calls the generic EvictorAPIUpsertAdvancedConfig builder with application/json body
+func NewEvictorAPIUpsertAdvancedConfigRequest(server string, clusterId string, body EvictorAPIUpsertAdvancedConfigJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewEvictorAPIUpsertAdvancedConfigRequestWithBody(server, clusterId, "application/json", bodyReader)
+}
+
+// NewEvictorAPIUpsertAdvancedConfigRequestWithBody generates requests for EvictorAPIUpsertAdvancedConfig with any type of body
+func NewEvictorAPIUpsertAdvancedConfigRequestWithBody(server string, clusterId string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithLocation("simple", false, "clusterId", runtime.ParamLocationPath, clusterId)
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/v1/kubernetes/clusters/%s/evictor-advanced-config", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest("POST", queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
// NewNodeTemplatesAPIFilterInstanceTypesRequest calls the generic NodeTemplatesAPIFilterInstanceTypes builder with application/json body
func NewNodeTemplatesAPIFilterInstanceTypesRequest(server string, clusterId string, body NodeTemplatesAPIFilterInstanceTypesJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
@@ -4972,6 +5097,14 @@ type ClientWithResponsesInterface interface {
ClaimInvitationWithResponse(ctx context.Context, id string, body ClaimInvitationJSONRequestBody) (*ClaimInvitationResponse, error)
+ // EvictorAPIGetAdvancedConfig request
+ EvictorAPIGetAdvancedConfigWithResponse(ctx context.Context, clusterId string) (*EvictorAPIGetAdvancedConfigResponse, error)
+
+ // EvictorAPIUpsertAdvancedConfig request with any body
+ EvictorAPIUpsertAdvancedConfigWithBodyWithResponse(ctx context.Context, clusterId string, contentType string, body io.Reader) (*EvictorAPIUpsertAdvancedConfigResponse, error)
+
+ EvictorAPIUpsertAdvancedConfigWithResponse(ctx context.Context, clusterId string, body EvictorAPIUpsertAdvancedConfigJSONRequestBody) (*EvictorAPIUpsertAdvancedConfigResponse, error)
+
// NodeTemplatesAPIFilterInstanceTypes request with any body
NodeTemplatesAPIFilterInstanceTypesWithBodyWithResponse(ctx context.Context, clusterId string, contentType string, body io.Reader) (*NodeTemplatesAPIFilterInstanceTypesResponse, error)
@@ -5504,6 +5637,66 @@ func (r ClaimInvitationResponse) GetBody() []byte {
// TODO: to have common interface. https://github.com/deepmap/oapi-codegen/issues/240
+type EvictorAPIGetAdvancedConfigResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *CastaiEvictorV1AdvancedConfig
+}
+
+// Status returns HTTPResponse.Status
+func (r EvictorAPIGetAdvancedConfigResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r EvictorAPIGetAdvancedConfigResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// TODO: to have common interface. https://github.com/deepmap/oapi-codegen/issues/240
+// Body returns body of byte array
+func (r EvictorAPIGetAdvancedConfigResponse) GetBody() []byte {
+ return r.Body
+}
+
+// TODO: to have common interface. https://github.com/deepmap/oapi-codegen/issues/240
+
+type EvictorAPIUpsertAdvancedConfigResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *CastaiEvictorV1AdvancedConfig
+}
+
+// Status returns HTTPResponse.Status
+func (r EvictorAPIUpsertAdvancedConfigResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r EvictorAPIUpsertAdvancedConfigResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// TODO: to have common interface. https://github.com/deepmap/oapi-codegen/issues/240
+// Body returns body of byte array
+func (r EvictorAPIUpsertAdvancedConfigResponse) GetBody() []byte {
+ return r.Body
+}
+
+// TODO: to have common interface. https://github.com/deepmap/oapi-codegen/issues/240
+
type NodeTemplatesAPIFilterInstanceTypesResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -7654,6 +7847,32 @@ func (c *ClientWithResponses) ClaimInvitationWithResponse(ctx context.Context, i
return ParseClaimInvitationResponse(rsp)
}
+// EvictorAPIGetAdvancedConfigWithResponse request returning *EvictorAPIGetAdvancedConfigResponse
+func (c *ClientWithResponses) EvictorAPIGetAdvancedConfigWithResponse(ctx context.Context, clusterId string) (*EvictorAPIGetAdvancedConfigResponse, error) {
+ rsp, err := c.EvictorAPIGetAdvancedConfig(ctx, clusterId)
+ if err != nil {
+ return nil, err
+ }
+ return ParseEvictorAPIGetAdvancedConfigResponse(rsp)
+}
+
+// EvictorAPIUpsertAdvancedConfigWithBodyWithResponse request with arbitrary body returning *EvictorAPIUpsertAdvancedConfigResponse
+func (c *ClientWithResponses) EvictorAPIUpsertAdvancedConfigWithBodyWithResponse(ctx context.Context, clusterId string, contentType string, body io.Reader) (*EvictorAPIUpsertAdvancedConfigResponse, error) {
+ rsp, err := c.EvictorAPIUpsertAdvancedConfigWithBody(ctx, clusterId, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ return ParseEvictorAPIUpsertAdvancedConfigResponse(rsp)
+}
+
+func (c *ClientWithResponses) EvictorAPIUpsertAdvancedConfigWithResponse(ctx context.Context, clusterId string, body EvictorAPIUpsertAdvancedConfigJSONRequestBody) (*EvictorAPIUpsertAdvancedConfigResponse, error) {
+ rsp, err := c.EvictorAPIUpsertAdvancedConfig(ctx, clusterId, body)
+ if err != nil {
+ return nil, err
+ }
+ return ParseEvictorAPIUpsertAdvancedConfigResponse(rsp)
+}
+
// NodeTemplatesAPIFilterInstanceTypesWithBodyWithResponse request with arbitrary body returning *NodeTemplatesAPIFilterInstanceTypesResponse
func (c *ClientWithResponses) NodeTemplatesAPIFilterInstanceTypesWithBodyWithResponse(ctx context.Context, clusterId string, contentType string, body io.Reader) (*NodeTemplatesAPIFilterInstanceTypesResponse, error) {
rsp, err := c.NodeTemplatesAPIFilterInstanceTypesWithBody(ctx, clusterId, contentType, body)
@@ -8692,6 +8911,58 @@ func ParseClaimInvitationResponse(rsp *http.Response) (*ClaimInvitationResponse,
return response, nil
}
+// ParseEvictorAPIGetAdvancedConfigResponse parses an HTTP response from a EvictorAPIGetAdvancedConfigWithResponse call
+func ParseEvictorAPIGetAdvancedConfigResponse(rsp *http.Response) (*EvictorAPIGetAdvancedConfigResponse, error) {
+ bodyBytes, err := ioutil.ReadAll(rsp.Body)
+ defer rsp.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &EvictorAPIGetAdvancedConfigResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest CastaiEvictorV1AdvancedConfig
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseEvictorAPIUpsertAdvancedConfigResponse parses an HTTP response from a EvictorAPIUpsertAdvancedConfigWithResponse call
+func ParseEvictorAPIUpsertAdvancedConfigResponse(rsp *http.Response) (*EvictorAPIUpsertAdvancedConfigResponse, error) {
+ bodyBytes, err := ioutil.ReadAll(rsp.Body)
+ defer rsp.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &EvictorAPIUpsertAdvancedConfigResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest CastaiEvictorV1AdvancedConfig
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
// ParseNodeTemplatesAPIFilterInstanceTypesResponse parses an HTTP response from a NodeTemplatesAPIFilterInstanceTypesWithResponse call
func ParseNodeTemplatesAPIFilterInstanceTypesResponse(rsp *http.Response) (*NodeTemplatesAPIFilterInstanceTypesResponse, error) {
bodyBytes, err := ioutil.ReadAll(rsp.Body)
diff --git a/castai/sdk/mock/client.go b/castai/sdk/mock/client.go
index 028c4af7..73d2782a 100644
--- a/castai/sdk/mock/client.go
+++ b/castai/sdk/mock/client.go
@@ -455,6 +455,66 @@ func (mr *MockClientInterfaceMockRecorder) DeleteOrganizationUser(ctx, id, userI
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOrganizationUser", reflect.TypeOf((*MockClientInterface)(nil).DeleteOrganizationUser), varargs...)
}
+// EvictorAPIGetAdvancedConfig mocks base method.
+func (m *MockClientInterface) EvictorAPIGetAdvancedConfig(ctx context.Context, clusterId string, reqEditors ...sdk.RequestEditorFn) (*http.Response, error) {
+ m.ctrl.T.Helper()
+ varargs := []interface{}{ctx, clusterId}
+ for _, a := range reqEditors {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "EvictorAPIGetAdvancedConfig", varargs...)
+ ret0, _ := ret[0].(*http.Response)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// EvictorAPIGetAdvancedConfig indicates an expected call of EvictorAPIGetAdvancedConfig.
+func (mr *MockClientInterfaceMockRecorder) EvictorAPIGetAdvancedConfig(ctx, clusterId interface{}, reqEditors ...interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]interface{}{ctx, clusterId}, reqEditors...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvictorAPIGetAdvancedConfig", reflect.TypeOf((*MockClientInterface)(nil).EvictorAPIGetAdvancedConfig), varargs...)
+}
+
+// EvictorAPIUpsertAdvancedConfig mocks base method.
+func (m *MockClientInterface) EvictorAPIUpsertAdvancedConfig(ctx context.Context, clusterId string, body sdk.EvictorAPIUpsertAdvancedConfigJSONRequestBody, reqEditors ...sdk.RequestEditorFn) (*http.Response, error) {
+ m.ctrl.T.Helper()
+ varargs := []interface{}{ctx, clusterId, body}
+ for _, a := range reqEditors {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "EvictorAPIUpsertAdvancedConfig", varargs...)
+ ret0, _ := ret[0].(*http.Response)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// EvictorAPIUpsertAdvancedConfig indicates an expected call of EvictorAPIUpsertAdvancedConfig.
+func (mr *MockClientInterfaceMockRecorder) EvictorAPIUpsertAdvancedConfig(ctx, clusterId, body interface{}, reqEditors ...interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]interface{}{ctx, clusterId, body}, reqEditors...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvictorAPIUpsertAdvancedConfig", reflect.TypeOf((*MockClientInterface)(nil).EvictorAPIUpsertAdvancedConfig), varargs...)
+}
+
+// EvictorAPIUpsertAdvancedConfigWithBody mocks base method.
+func (m *MockClientInterface) EvictorAPIUpsertAdvancedConfigWithBody(ctx context.Context, clusterId, contentType string, body io.Reader, reqEditors ...sdk.RequestEditorFn) (*http.Response, error) {
+ m.ctrl.T.Helper()
+ varargs := []interface{}{ctx, clusterId, contentType, body}
+ for _, a := range reqEditors {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "EvictorAPIUpsertAdvancedConfigWithBody", varargs...)
+ ret0, _ := ret[0].(*http.Response)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// EvictorAPIUpsertAdvancedConfigWithBody indicates an expected call of EvictorAPIUpsertAdvancedConfigWithBody.
+func (mr *MockClientInterfaceMockRecorder) EvictorAPIUpsertAdvancedConfigWithBody(ctx, clusterId, contentType, body interface{}, reqEditors ...interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]interface{}{ctx, clusterId, contentType, body}, reqEditors...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvictorAPIUpsertAdvancedConfigWithBody", reflect.TypeOf((*MockClientInterface)(nil).EvictorAPIUpsertAdvancedConfigWithBody), varargs...)
+}
+
// ExternalClusterAPIAddNode mocks base method.
func (m *MockClientInterface) ExternalClusterAPIAddNode(ctx context.Context, clusterId string, body sdk.ExternalClusterAPIAddNodeJSONRequestBody, reqEditors ...sdk.RequestEditorFn) (*http.Response, error) {
m.ctrl.T.Helper()
@@ -2483,6 +2543,51 @@ func (mr *MockClientWithResponsesInterfaceMockRecorder) DeleteOrganizationWithRe
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOrganizationWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).DeleteOrganizationWithResponse), ctx, id)
}
+// EvictorAPIGetAdvancedConfigWithResponse mocks base method.
+func (m *MockClientWithResponsesInterface) EvictorAPIGetAdvancedConfigWithResponse(ctx context.Context, clusterId string) (*sdk.EvictorAPIGetAdvancedConfigResponse, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "EvictorAPIGetAdvancedConfigWithResponse", ctx, clusterId)
+ ret0, _ := ret[0].(*sdk.EvictorAPIGetAdvancedConfigResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// EvictorAPIGetAdvancedConfigWithResponse indicates an expected call of EvictorAPIGetAdvancedConfigWithResponse.
+func (mr *MockClientWithResponsesInterfaceMockRecorder) EvictorAPIGetAdvancedConfigWithResponse(ctx, clusterId interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvictorAPIGetAdvancedConfigWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).EvictorAPIGetAdvancedConfigWithResponse), ctx, clusterId)
+}
+
+// EvictorAPIUpsertAdvancedConfigWithBodyWithResponse mocks base method.
+func (m *MockClientWithResponsesInterface) EvictorAPIUpsertAdvancedConfigWithBodyWithResponse(ctx context.Context, clusterId, contentType string, body io.Reader) (*sdk.EvictorAPIUpsertAdvancedConfigResponse, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "EvictorAPIUpsertAdvancedConfigWithBodyWithResponse", ctx, clusterId, contentType, body)
+ ret0, _ := ret[0].(*sdk.EvictorAPIUpsertAdvancedConfigResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// EvictorAPIUpsertAdvancedConfigWithBodyWithResponse indicates an expected call of EvictorAPIUpsertAdvancedConfigWithBodyWithResponse.
+func (mr *MockClientWithResponsesInterfaceMockRecorder) EvictorAPIUpsertAdvancedConfigWithBodyWithResponse(ctx, clusterId, contentType, body interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvictorAPIUpsertAdvancedConfigWithBodyWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).EvictorAPIUpsertAdvancedConfigWithBodyWithResponse), ctx, clusterId, contentType, body)
+}
+
+// EvictorAPIUpsertAdvancedConfigWithResponse mocks base method.
+func (m *MockClientWithResponsesInterface) EvictorAPIUpsertAdvancedConfigWithResponse(ctx context.Context, clusterId string, body sdk.EvictorAPIUpsertAdvancedConfigJSONRequestBody) (*sdk.EvictorAPIUpsertAdvancedConfigResponse, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "EvictorAPIUpsertAdvancedConfigWithResponse", ctx, clusterId, body)
+ ret0, _ := ret[0].(*sdk.EvictorAPIUpsertAdvancedConfigResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// EvictorAPIUpsertAdvancedConfigWithResponse indicates an expected call of EvictorAPIUpsertAdvancedConfigWithResponse.
+func (mr *MockClientWithResponsesInterfaceMockRecorder) EvictorAPIUpsertAdvancedConfigWithResponse(ctx, clusterId, body interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EvictorAPIUpsertAdvancedConfigWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).EvictorAPIUpsertAdvancedConfigWithResponse), ctx, clusterId, body)
+}
+
// ExternalClusterAPIAddNodeWithBodyWithResponse mocks base method.
func (m *MockClientWithResponsesInterface) ExternalClusterAPIAddNodeWithBodyWithResponse(ctx context.Context, clusterId, contentType string, body io.Reader) (*sdk.ExternalClusterAPIAddNodeResponse, error) {
m.ctrl.T.Helper()
diff --git a/docs/resources/evictor_advanced_config.md b/docs/resources/evictor_advanced_config.md
new file mode 100644
index 00000000..1a0fed02
--- /dev/null
+++ b/docs/resources/evictor_advanced_config.md
@@ -0,0 +1,97 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "castai_evictor_advanced_config Resource - terraform-provider-castai"
+subcategory: ""
+description: |-
+ CAST AI eviction config resource to manage evictor properties
+---
+
+# castai_evictor_advanced_config (Resource)
+
+CAST AI eviction config resource to manage evictor properties
+
+
+
+
+## Schema
+
+### Required
+
+- `evictor_advanced_config` (Block List, Min: 1) evictor advanced configuration to target specific node/pod (see [below for nested schema](#nestedblock--evictor_advanced_config))
+
+### Optional
+
+- `cluster_id` (String) CAST AI cluster id.
+- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `evictor_advanced_config`
+
+Optional:
+
+- `aggressive` (Boolean)
+- `disposable` (Boolean)
+- `node_selector` (Block List) node selector (see [below for nested schema](#nestedblock--evictor_advanced_config--node_selector))
+- `pod_selector` (Block List) pod selector (see [below for nested schema](#nestedblock--evictor_advanced_config--pod_selector))
+- `removal_disabled` (Boolean)
+
+
+### Nested Schema for `evictor_advanced_config.node_selector`
+
+Optional:
+
+- `match_expressions` (Block List) (see [below for nested schema](#nestedblock--evictor_advanced_config--node_selector--match_expressions))
+- `match_labels` (Map of String)
+
+
+### Nested Schema for `evictor_advanced_config.node_selector.match_expressions`
+
+Required:
+
+- `key` (String)
+- `operator` (String)
+
+Optional:
+
+- `values` (List of String)
+
+
+
+
+### Nested Schema for `evictor_advanced_config.pod_selector`
+
+Optional:
+
+- `kind` (String)
+- `match_expressions` (Block List) (see [below for nested schema](#nestedblock--evictor_advanced_config--pod_selector--match_expressions))
+- `match_labels` (Map of String)
+- `namespace` (String)
+
+
+### Nested Schema for `evictor_advanced_config.pod_selector.match_expressions`
+
+Required:
+
+- `key` (String)
+- `operator` (String)
+
+Optional:
+
+- `values` (List of String)
+
+
+
+
+
+### Nested Schema for `timeouts`
+
+Optional:
+
+- `create` (String)
+- `update` (String)
+
+
diff --git a/examples/gke/evictor_advanced_config/README.MD b/examples/gke/evictor_advanced_config/README.MD
new file mode 100644
index 00000000..c94f6dcc
--- /dev/null
+++ b/examples/gke/evictor_advanced_config/README.MD
@@ -0,0 +1,28 @@
+## GKE and CAST AI example with CAST AI Autoscaler evictor advanced config
+
+Following example shows how to onboard GKE cluster to CAST AI, configure [Autoscaler evictor advanced config](https://docs.cast.ai/docs/evictor-advanced-configuration)
+
+IAM policies required to connect the cluster to CAST AI in the example are created by [castai/gke-role-iam/castai module](https://github.com/castai/terraform-castai-gke-iam).
+
+This example builds on top of gke_cluster_autoscaler_policies example. Please refer to it for more details.
+
+Example configuration should be analysed in the following order:
+1. Create VPC - `vpc.tf`
+2. Create GKE cluster - `gke.tf`
+3. Create IAM and other CAST AI related resources to connect GKE cluster to CAST AI, configure Autoscaler and Node Configurations - `castai.tf`
+
+# Usage
+1. Rename `tf.vars.example` to `tf.vars`
+2. Update `tf.vars` file with your project name, cluster name, cluster region and CAST AI API token.
+3. Initialize Terraform. Under example root folder run:
+```
+terraform init
+```
+4. Run Terraform apply:
+```
+terraform apply -var-file=tf.vars
+```
+5. To destroy resources created by this example:
+```
+terraform destroy -var-file=tf.vars
+```
diff --git a/examples/gke/evictor_advanced_config/castai.tf b/examples/gke/evictor_advanced_config/castai.tf
new file mode 100644
index 00000000..bb924bfb
--- /dev/null
+++ b/examples/gke/evictor_advanced_config/castai.tf
@@ -0,0 +1,39 @@
+provider "castai" {
+ api_url = var.castai_api_url
+ api_token = var.castai_api_token
+}
+
+module "gke_autoscaler_evictor_advanced_config" {
+ source = "../gke_cluster_autoscaler_policies"
+
+ castai_api_token = var.castai_api_token
+ castai_api_url = var.castai_api_url
+ cluster_region = var.cluster_region
+ cluster_zones = var.cluster_zones
+ cluster_name = var.cluster_name
+ project_id = var.project_id
+ delete_nodes_on_disconnect = var.delete_nodes_on_disconnect
+ evictor_advanced_config = [
+ {
+ pod_selector = {
+ kind = "Job"
+ namespace = "castai"
+ match_labels = {
+ "app.kubernetes.io/name" = "castai-node"
+ }
+ },
+ aggressive = true
+ },
+ {
+ node_selector = {
+ match_expressions = [
+ {
+ key = "pod.cast.ai/flag"
+ operator = "Exists"
+ }
+ ]
+ },
+ disposable = true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/gke/evictor_advanced_config/variables.tf b/examples/gke/evictor_advanced_config/variables.tf
new file mode 100644
index 00000000..53a46b10
--- /dev/null
+++ b/examples/gke/evictor_advanced_config/variables.tf
@@ -0,0 +1,44 @@
+# GKE module variables.
+variable "cluster_name" {
+ type = string
+ description = "GKE cluster name in GCP project."
+}
+
+variable "cluster_region" {
+ type = string
+ description = "The region to create the cluster."
+}
+
+variable "cluster_zones" {
+ type = list(string)
+ description = "The zones to create the cluster."
+}
+
+variable "project_id" {
+ type = string
+ description = "GCP project ID in which GKE cluster would be created."
+}
+
+variable "castai_api_url" {
+ type = string
+ description = "URL of alternative CAST AI API to be used during development or testing"
+ default = "https://api-tiberiugal2.localenv.cast.ai"
+}
+
+# Variables required for connecting EKS cluster to CAST AI
+variable "castai_api_token" {
+ type = string
+ description = "CAST AI API token created in console.cast.ai API Access keys section."
+}
+
+variable "delete_nodes_on_disconnect" {
+ type = bool
+ description = "Optional parameter, if set to true - CAST AI provisioned nodes will be deleted from cloud on cluster disconnection. For production use it is recommended to set it to false."
+ default = true
+}
+
+variable "tags" {
+ type = map(any)
+ description = "Optional tags for new cluster nodes. This parameter applies only to new nodes - tags for old nodes are not reconciled."
+ default = {}
+}
diff --git a/examples/gke/gke_cluster_zonal_autoscaler/version.tf b/examples/gke/gke_cluster_zonal_autoscaler/version.tf
index 67109f91..d19e42bd 100644
--- a/examples/gke/gke_cluster_zonal_autoscaler/version.tf
+++ b/examples/gke/gke_cluster_zonal_autoscaler/version.tf
@@ -14,4 +14,4 @@ terraform {
}
}
required_version = ">= 0.13"
-}
+}
\ No newline at end of file