diff --git a/castai/resource_node_template.go b/castai/resource_node_template.go index 0bc76427..f3c795d4 100644 --- a/castai/resource_node_template.go +++ b/castai/resource_node_template.go @@ -56,7 +56,7 @@ const ( FieldNodeTemplateStorageOptimized = "storage_optimized" FieldNodeTemplateUseSpotFallbacks = "use_spot_fallbacks" FieldNodeTemplateCustomPriority = "custom_priority" - FieldNodeTemplateNodeAffinity = "node_affinity" + FieldNodeTemplateDedicatedNodeAffinity = "dedicated_node_affinity" FieldNodeTemplateAzName = "az_name" FieldNodeTemplateInstanceTypes = "instance_types" ) @@ -348,9 +348,10 @@ func resourceNodeTemplate() *schema.Resource { }, }, }, - FieldNodeTemplateNodeAffinity: { - Type: schema.TypeList, - Optional: true, + FieldNodeTemplateDedicatedNodeAffinity: { + Type: schema.TypeList, + Optional: true, + Description: "Dedicated node affinity - creates preference for instances to be created on sole tenancy or dedicated nodes. This\n feature is only available for GCP clusters, requires feature flag to be enabled and sole tenancy nodes with local\n SSDs or GPUs are not supported. If the sole tenancy or dedicated nodes don't have capacity for selected instance\n type, the Autoscaler will fall back to multi-tenant instance types available for this Node Template.\n Other instance constraints are applied when the Autoscaler picks available instance types that can be created on\n the sole tenancy or dedicated node (example: setting min CPU to 16).", Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ FieldNodeTemplateInstanceTypes: { @@ -359,7 +360,7 @@ func resourceNodeTemplate() *schema.Resource { Elem: &schema.Schema{ Type: schema.TypeString, }, - Description: "Instance types in this node group.", + Description: "Instance/node types in this node group.", }, FieldNodeTemplateAzName: { Required: true, @@ -518,8 +519,8 @@ func flattenConstraints(c *sdk.NodetemplatesV1TemplateConstraints) ([]map[string if c.CustomPriority != nil && len(*c.CustomPriority) > 0 { out[FieldNodeTemplateCustomPriority] = flattenCustomPriority(*c.CustomPriority) } - if c.NodeAffinity != nil && len(*c.NodeAffinity) > 0 { - out[FieldNodeTemplateNodeAffinity] = flattenNodeAffinity(*c.NodeAffinity) + if c.DedicatedNodeAffinity != nil && len(*c.DedicatedNodeAffinity) > 0 { + out[FieldNodeTemplateDedicatedNodeAffinity] = flattenNodeAffinity(*c.DedicatedNodeAffinity) } if c.InstanceFamilies != nil { out[FieldNodeTemplateInstanceFamilies] = flattenInstanceFamilies(c.InstanceFamilies) @@ -628,8 +629,8 @@ func flattenCustomPriority(priorities []sdk.NodetemplatesV1TemplateConstraintsCu }) } -func flattenNodeAffinity(affinities []sdk.NodetemplatesV1TemplateConstraintsNodeAffinity) any { - return lo.Map(affinities, func(item sdk.NodetemplatesV1TemplateConstraintsNodeAffinity, index int) map[string]any { +func flattenNodeAffinity(affinities []sdk.NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity) any { + return lo.Map(affinities, func(item sdk.NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity, index int) map[string]any { result := map[string]any{} if item.InstanceTypes != nil { result[FieldNodeTemplateInstanceTypes] = *item.InstanceTypes @@ -1064,16 +1065,16 @@ func toTemplateConstraints(obj map[string]any) *sdk.NodetemplatesV1TemplateConst })) } } - if v, ok := obj[FieldNodeTemplateNodeAffinity].([]any); ok && len(v) > 0 { + if v, ok := obj[FieldNodeTemplateDedicatedNodeAffinity].([]any); ok && len(v) > 0 { if ok { - out.NodeAffinity = lo.ToPtr(lo.FilterMap(v, func(item any, _ int) (sdk.NodetemplatesV1TemplateConstraintsNodeAffinity, bool) { + out.DedicatedNodeAffinity = lo.ToPtr(lo.FilterMap(v, func(item any, _ int) (sdk.NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity, bool) { val, ok := item.(map[string]any) if !ok { - return sdk.NodetemplatesV1TemplateConstraintsNodeAffinity{}, false + return sdk.NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity{}, false } res := toTemplateConstraintsNodeAffinity(val) if res == nil { - return sdk.NodetemplatesV1TemplateConstraintsNodeAffinity{}, false + return sdk.NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity{}, false } return *res, true })) @@ -1144,12 +1145,12 @@ func toTemplateConstraintsCustomPriority(o map[string]any) *sdk.NodetemplatesV1T return &out } -func toTemplateConstraintsNodeAffinity(o map[string]any) *sdk.NodetemplatesV1TemplateConstraintsNodeAffinity { +func toTemplateConstraintsNodeAffinity(o map[string]any) *sdk.NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity { if o == nil { return nil } - out := sdk.NodetemplatesV1TemplateConstraintsNodeAffinity{} + out := sdk.NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity{} if v, ok := o[FieldNodeTemplateName].(string); ok { out.Name = toPtr(v) } diff --git a/castai/resource_node_template_test.go b/castai/resource_node_template_test.go index af1c439c..1dc79907 100644 --- a/castai/resource_node_template_test.go +++ b/castai/resource_node_template_test.go @@ -88,7 +88,7 @@ func TestNodeTemplateResourceReadContext(t *testing.T) { "onDemand": true } ], - "nodeAffinity": [ + "dedicatedNodeAffinity": [ { "name": "foo", "azName": "eu-central-1a", @@ -178,11 +178,11 @@ constraints.0.max_cpu = 10000 constraints.0.max_memory = 0 constraints.0.min_cpu = 10 constraints.0.min_memory = 0 -constraints.0.node_affinity.# = 1 -constraints.0.node_affinity.0.az_name = eu-central-1a -constraints.0.node_affinity.0.instance_types.# = 1 -constraints.0.node_affinity.0.instance_types.0 = m5.24xlarge -constraints.0.node_affinity.0.name = foo +constraints.0.dedicated_node_affinity.# = 1 +constraints.0.dedicated_node_affinity.0.az_name = eu-central-1a +constraints.0.dedicated_node_affinity.0.instance_types.# = 1 +constraints.0.dedicated_node_affinity.0.instance_types.0 = m5.24xlarge +constraints.0.dedicated_node_affinity.0.name = foo constraints.0.on_demand = true constraints.0.os.# = 1 constraints.0.os.0 = linux @@ -446,7 +446,7 @@ func TestAccResourceNodeTemplate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "constraints.0.custom_priority.0.instance_families.1", "d"), resource.TestCheckResourceAttr(resourceName, "constraints.0.custom_priority.0.spot", "true"), resource.TestCheckResourceAttr(resourceName, "constraints.0.custom_priority.0.on_demand", "true"), - resource.TestCheckResourceAttr(resourceName, "constraints.0.node_affinity.#", "0"), + resource.TestCheckResourceAttr(resourceName, "constraints.0.dedicated_node_affinity.#", "0"), ), }, { @@ -504,7 +504,7 @@ func TestAccResourceNodeTemplate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "constraints.0.custom_priority.1.instance_families.1", "d"), resource.TestCheckResourceAttr(resourceName, "constraints.0.custom_priority.1.spot", "true"), resource.TestCheckResourceAttr(resourceName, "constraints.0.custom_priority.1.on_demand", "true"), - resource.TestCheckResourceAttr(resourceName, "constraints.0.node_affinity.#", "0"), + resource.TestCheckResourceAttr(resourceName, "constraints.0.dedicated_node_affinity.#", "0"), ), }, }, diff --git a/castai/sdk/api.gen.go b/castai/sdk/api.gen.go index a2b994e2..bcaf31ec 100644 --- a/castai/sdk/api.gen.go +++ b/castai/sdk/api.gen.go @@ -1581,7 +1581,8 @@ type NodeconfigV1EKSConfig struct { KeyPairId *string `json:"keyPairId"` // Cluster's security groups configuration. - SecurityGroups *[]string `json:"securityGroups,omitempty"` + SecurityGroups *[]string `json:"securityGroups,omitempty"` + TargetGroup *NodeconfigV1TargetGroup `json:"targetGroup,omitempty"` // EBS volume IOPS value to be used for provisioned nodes. VolumeIops *int32 `json:"volumeIops"` @@ -1818,6 +1819,15 @@ type NodeconfigV1SubnetDetails_Tags struct { AdditionalProperties map[string]string `json:"-"` } +// NodeconfigV1TargetGroup defines model for nodeconfig.v1.TargetGroup. +type NodeconfigV1TargetGroup struct { + // ARN of the target group. + Arn *string `json:"arn,omitempty"` + + // Port of the target group. + Port *int32 `json:"port,omitempty"` +} + // NodetemplatesV1AvailableInstanceType defines model for nodetemplates.v1.AvailableInstanceType. type NodetemplatesV1AvailableInstanceType struct { Architecture *string `json:"architecture,omitempty"` @@ -1854,6 +1864,11 @@ type NodetemplatesV1FilterInstanceTypesResponse struct { AvailableInstanceTypes *[]NodetemplatesV1AvailableInstanceType `json:"availableInstanceTypes,omitempty"` } +// NodetemplatesV1GenerateNodeTemplatesResponse defines model for nodetemplates.v1.GenerateNodeTemplatesResponse. +type NodetemplatesV1GenerateNodeTemplatesResponse struct { + Items *[]NodetemplatesV1NodeTemplateListItem `json:"items,omitempty"` +} + // NodetemplatesV1Label defines model for nodetemplates.v1.Label. type NodetemplatesV1Label struct { Key *string `json:"key,omitempty"` @@ -1982,6 +1997,16 @@ type NodetemplatesV1TemplateConstraints struct { // Custom sorting priority - instances matching defined rules will take priority over other candidates. CustomPriority *[]NodetemplatesV1TemplateConstraintsCustomPriority `json:"customPriority,omitempty"` + // Dedicated node affinity - creates preference for instances to be created on sole tenancy or dedicated nodes. + // + // Dedicated node affinity - creates preference for instances to be created on sole tenancy or dedicated nodes. This + // feature is only available for GCP clusters, requires feature flag to be enabled and sole tenancy nodes with local + // SSDs or GPUs are not supported. If the sole tenancy or dedicated nodes don't have capacity for selected instance + // type, the Autoscaler will fall back to multi-tenant instance types available for this Node Template. + // Other instance constraints are applied when the Autoscaler picks available instance types that can be created on + // the sole tenancy or dedicated node (example: setting min CPU to 16). + DedicatedNodeAffinity *[]NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity `json:"dedicatedNodeAffinity,omitempty"` + // Enable/disable spot diversity policy. When enabled, autoscaler will try to balance between diverse and cost optimal instance types. EnableSpotDiversity *bool `json:"enableSpotDiversity"` @@ -1992,12 +2017,11 @@ type NodetemplatesV1TemplateConstraints struct { // This template is gpu only. Setting this to true, will result in only instances with GPUs being considered. // In addition, this ensures that all of the added instances for this template won't have any nvidia taints. - IsGpuOnly *bool `json:"isGpuOnly"` - MaxCpu *int32 `json:"maxCpu"` - MaxMemory *int32 `json:"maxMemory"` - MinCpu *int32 `json:"minCpu"` - MinMemory *int32 `json:"minMemory"` - NodeAffinity *[]NodetemplatesV1TemplateConstraintsNodeAffinity `json:"nodeAffinity,omitempty"` + IsGpuOnly *bool `json:"isGpuOnly"` + MaxCpu *int32 `json:"maxCpu"` + MaxMemory *int32 `json:"maxMemory"` + MinCpu *int32 `json:"minCpu"` + MinMemory *int32 `json:"minMemory"` // Should include on-demand instances in the considered pool. OnDemand *bool `json:"onDemand"` @@ -2037,6 +2061,13 @@ type NodetemplatesV1TemplateConstraintsCustomPriority struct { Spot *bool `json:"spot"` } +// NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity defines model for nodetemplates.v1.TemplateConstraints.DedicatedNodeAffinity. +type NodetemplatesV1TemplateConstraintsDedicatedNodeAffinity struct { + AzName *string `json:"azName,omitempty"` + InstanceTypes *[]string `json:"instanceTypes,omitempty"` + Name *string `json:"name,omitempty"` +} + // NodetemplatesV1TemplateConstraintsGPUConstraints defines model for nodetemplates.v1.TemplateConstraints.GPUConstraints. type NodetemplatesV1TemplateConstraintsGPUConstraints struct { ExcludeNames *[]string `json:"excludeNames,omitempty"` @@ -2052,13 +2083,6 @@ type NodetemplatesV1TemplateConstraintsInstanceFamilyConstraints struct { Include *[]string `json:"include,omitempty"` } -// NodetemplatesV1TemplateConstraintsNodeAffinity defines model for nodetemplates.v1.TemplateConstraints.NodeAffinity. -type NodetemplatesV1TemplateConstraintsNodeAffinity struct { - AzName *string `json:"azName,omitempty"` - InstanceTypes *[]string `json:"instanceTypes,omitempty"` - Name *string `json:"name,omitempty"` -} - // NodetemplatesV1UpdateNodeTemplate defines model for nodetemplates.v1.UpdateNodeTemplate. type NodetemplatesV1UpdateNodeTemplate struct { ConfigurationId *string `json:"configurationId,omitempty"` diff --git a/castai/sdk/client.gen.go b/castai/sdk/client.gen.go index 33a1c432..c6595b3a 100644 --- a/castai/sdk/client.gen.go +++ b/castai/sdk/client.gen.go @@ -138,6 +138,9 @@ type ClientInterface interface { NodeTemplatesAPIFilterInstanceTypes(ctx context.Context, clusterId string, body NodeTemplatesAPIFilterInstanceTypesJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // NodeTemplatesAPIGenerateNodeTemplates request + NodeTemplatesAPIGenerateNodeTemplates(ctx context.Context, clusterId string, reqEditors ...RequestEditorFn) (*http.Response, error) + // NodeConfigurationAPIListConfigurations request NodeConfigurationAPIListConfigurations(ctx context.Context, clusterId string, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -629,6 +632,18 @@ func (c *Client) NodeTemplatesAPIFilterInstanceTypes(ctx context.Context, cluste return c.Client.Do(req) } +func (c *Client) NodeTemplatesAPIGenerateNodeTemplates(ctx context.Context, clusterId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewNodeTemplatesAPIGenerateNodeTemplatesRequest(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) NodeConfigurationAPIListConfigurations(ctx context.Context, clusterId string, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewNodeConfigurationAPIListConfigurationsRequest(c.Server, clusterId) if err != nil { @@ -2343,6 +2358,40 @@ func NewNodeTemplatesAPIFilterInstanceTypesRequestWithBody(server string, cluste return req, nil } +// NewNodeTemplatesAPIGenerateNodeTemplatesRequest generates requests for NodeTemplatesAPIGenerateNodeTemplates +func NewNodeTemplatesAPIGenerateNodeTemplatesRequest(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/generate-node-templates", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewNodeConfigurationAPIListConfigurationsRequest generates requests for NodeConfigurationAPIListConfigurations func NewNodeConfigurationAPIListConfigurationsRequest(server string, clusterId string) (*http.Request, error) { var err error @@ -5522,6 +5571,9 @@ type ClientWithResponsesInterface interface { NodeTemplatesAPIFilterInstanceTypesWithResponse(ctx context.Context, clusterId string, body NodeTemplatesAPIFilterInstanceTypesJSONRequestBody) (*NodeTemplatesAPIFilterInstanceTypesResponse, error) + // NodeTemplatesAPIGenerateNodeTemplates request + NodeTemplatesAPIGenerateNodeTemplatesWithResponse(ctx context.Context, clusterId string) (*NodeTemplatesAPIGenerateNodeTemplatesResponse, error) + // NodeConfigurationAPIListConfigurations request NodeConfigurationAPIListConfigurationsWithResponse(ctx context.Context, clusterId string) (*NodeConfigurationAPIListConfigurationsResponse, error) @@ -6166,6 +6218,36 @@ func (r NodeTemplatesAPIFilterInstanceTypesResponse) GetBody() []byte { // TODO: to have common interface. https://github.com/deepmap/oapi-codegen/issues/240 +type NodeTemplatesAPIGenerateNodeTemplatesResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *NodetemplatesV1GenerateNodeTemplatesResponse +} + +// Status returns HTTPResponse.Status +func (r NodeTemplatesAPIGenerateNodeTemplatesResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r NodeTemplatesAPIGenerateNodeTemplatesResponse) 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 NodeTemplatesAPIGenerateNodeTemplatesResponse) GetBody() []byte { + return r.Body +} + +// TODO: to have common interface. https://github.com/deepmap/oapi-codegen/issues/240 + type NodeConfigurationAPIListConfigurationsResponse struct { Body []byte HTTPResponse *http.Response @@ -8539,6 +8621,15 @@ func (c *ClientWithResponses) NodeTemplatesAPIFilterInstanceTypesWithResponse(ct return ParseNodeTemplatesAPIFilterInstanceTypesResponse(rsp) } +// NodeTemplatesAPIGenerateNodeTemplatesWithResponse request returning *NodeTemplatesAPIGenerateNodeTemplatesResponse +func (c *ClientWithResponses) NodeTemplatesAPIGenerateNodeTemplatesWithResponse(ctx context.Context, clusterId string) (*NodeTemplatesAPIGenerateNodeTemplatesResponse, error) { + rsp, err := c.NodeTemplatesAPIGenerateNodeTemplates(ctx, clusterId) + if err != nil { + return nil, err + } + return ParseNodeTemplatesAPIGenerateNodeTemplatesResponse(rsp) +} + // NodeConfigurationAPIListConfigurationsWithResponse request returning *NodeConfigurationAPIListConfigurationsResponse func (c *ClientWithResponses) NodeConfigurationAPIListConfigurationsWithResponse(ctx context.Context, clusterId string) (*NodeConfigurationAPIListConfigurationsResponse, error) { rsp, err := c.NodeConfigurationAPIListConfigurations(ctx, clusterId) @@ -9725,6 +9816,32 @@ func ParseNodeTemplatesAPIFilterInstanceTypesResponse(rsp *http.Response) (*Node return response, nil } +// ParseNodeTemplatesAPIGenerateNodeTemplatesResponse parses an HTTP response from a NodeTemplatesAPIGenerateNodeTemplatesWithResponse call +func ParseNodeTemplatesAPIGenerateNodeTemplatesResponse(rsp *http.Response) (*NodeTemplatesAPIGenerateNodeTemplatesResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer rsp.Body.Close() + if err != nil { + return nil, err + } + + response := &NodeTemplatesAPIGenerateNodeTemplatesResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest NodetemplatesV1GenerateNodeTemplatesResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + // ParseNodeConfigurationAPIListConfigurationsResponse parses an HTTP response from a NodeConfigurationAPIListConfigurationsWithResponse call func ParseNodeConfigurationAPIListConfigurationsResponse(rsp *http.Response) (*NodeConfigurationAPIListConfigurationsResponse, error) { bodyBytes, err := ioutil.ReadAll(rsp.Body) diff --git a/castai/sdk/mock/client.go b/castai/sdk/mock/client.go index 95bd76f6..a134930f 100644 --- a/castai/sdk/mock/client.go +++ b/castai/sdk/mock/client.go @@ -1355,6 +1355,26 @@ func (mr *MockClientInterfaceMockRecorder) NodeTemplatesAPIFilterInstanceTypesWi return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeTemplatesAPIFilterInstanceTypesWithBody", reflect.TypeOf((*MockClientInterface)(nil).NodeTemplatesAPIFilterInstanceTypesWithBody), varargs...) } +// NodeTemplatesAPIGenerateNodeTemplates mocks base method. +func (m *MockClientInterface) NodeTemplatesAPIGenerateNodeTemplates(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, "NodeTemplatesAPIGenerateNodeTemplates", varargs...) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeTemplatesAPIGenerateNodeTemplates indicates an expected call of NodeTemplatesAPIGenerateNodeTemplates. +func (mr *MockClientInterfaceMockRecorder) NodeTemplatesAPIGenerateNodeTemplates(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, "NodeTemplatesAPIGenerateNodeTemplates", reflect.TypeOf((*MockClientInterface)(nil).NodeTemplatesAPIGenerateNodeTemplates), varargs...) +} + // NodeTemplatesAPIListNodeTemplates mocks base method. func (m *MockClientInterface) NodeTemplatesAPIListNodeTemplates(ctx context.Context, clusterId string, params *sdk.NodeTemplatesAPIListNodeTemplatesParams, reqEditors ...sdk.RequestEditorFn) (*http.Response, error) { m.ctrl.T.Helper() @@ -3418,6 +3438,21 @@ func (mr *MockClientWithResponsesInterfaceMockRecorder) NodeTemplatesAPIFilterIn return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeTemplatesAPIFilterInstanceTypesWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).NodeTemplatesAPIFilterInstanceTypesWithResponse), ctx, clusterId, body) } +// NodeTemplatesAPIGenerateNodeTemplatesWithResponse mocks base method. +func (m *MockClientWithResponsesInterface) NodeTemplatesAPIGenerateNodeTemplatesWithResponse(ctx context.Context, clusterId string) (*sdk.NodeTemplatesAPIGenerateNodeTemplatesResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NodeTemplatesAPIGenerateNodeTemplatesWithResponse", ctx, clusterId) + ret0, _ := ret[0].(*sdk.NodeTemplatesAPIGenerateNodeTemplatesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NodeTemplatesAPIGenerateNodeTemplatesWithResponse indicates an expected call of NodeTemplatesAPIGenerateNodeTemplatesWithResponse. +func (mr *MockClientWithResponsesInterfaceMockRecorder) NodeTemplatesAPIGenerateNodeTemplatesWithResponse(ctx, clusterId interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeTemplatesAPIGenerateNodeTemplatesWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).NodeTemplatesAPIGenerateNodeTemplatesWithResponse), ctx, clusterId) +} + // NodeTemplatesAPIListNodeTemplatesWithResponse mocks base method. func (m *MockClientWithResponsesInterface) NodeTemplatesAPIListNodeTemplatesWithResponse(ctx context.Context, clusterId string, params *sdk.NodeTemplatesAPIListNodeTemplatesParams) (*sdk.NodeTemplatesAPIListNodeTemplatesResponse, error) { m.ctrl.T.Helper() diff --git a/docs/resources/node_template.md b/docs/resources/node_template.md index 750e6eb3..02799826 100644 --- a/docs/resources/node_template.md +++ b/docs/resources/node_template.md @@ -46,6 +46,12 @@ Optional: - `architectures` (List of String) List of acceptable instance CPU architectures, the default is amd64. Allowed values: amd64, arm64. - `compute_optimized` (Boolean) Compute optimized instance constraint - will only pick compute optimized nodes if true. - `custom_priority` (Block List) (see [below for nested schema](#nestedblock--constraints--custom_priority)) +- `dedicated_node_affinity` (Block List) Dedicated node affinity - creates preference for instances to be created on sole tenancy or dedicated nodes. This + feature is only available for GCP clusters, requires feature flag to be enabled and sole tenancy nodes with local + SSDs or GPUs are not supported. If the sole tenancy or dedicated nodes don't have capacity for selected instance + type, the Autoscaler will fall back to multi-tenant instance types available for this Node Template. + Other instance constraints are applied when the Autoscaler picks available instance types that can be created on + the sole tenancy or dedicated node (example: setting min CPU to 16). (see [below for nested schema](#nestedblock--constraints--dedicated_node_affinity)) - `enable_spot_diversity` (Boolean) Enable/disable spot diversity policy. When enabled, autoscaler will try to balance between diverse and cost optimal instance types. - `fallback_restore_rate_seconds` (Number) Fallback restore rate in seconds: defines how much time should pass before spot fallback should be attempted to be restored to real spot. - `gpu` (Block List, Max: 1) (see [below for nested schema](#nestedblock--constraints--gpu)) @@ -55,7 +61,6 @@ Optional: - `max_memory` (Number) Max Memory (Mib) per node. - `min_cpu` (Number) Min CPU cores per node. - `min_memory` (Number) Min Memory (Mib) per node. -- `node_affinity` (Block List) (see [below for nested schema](#nestedblock--constraints--node_affinity)) - `on_demand` (Boolean) Should include on-demand instances in the considered pool. - `os` (List of String) List of acceptable instance Operating Systems, the default is linux. Allowed values: linux, windows. - `spot` (Boolean) Should include spot instances in the considered pool. @@ -75,6 +80,16 @@ Optional: - `spot` (Boolean) If true, this tier will apply to spot instances. + +### Nested Schema for `constraints.dedicated_node_affinity` + +Required: + +- `az_name` (String) Availability zone name. +- `instance_types` (List of String) Instance/node types in this node group. +- `name` (String) Name of node group. + + ### Nested Schema for `constraints.gpu` @@ -96,16 +111,6 @@ Optional: - `include` (List of String) Instance families to exclude when filtering (includes all other families). - -### Nested Schema for `constraints.node_affinity` - -Required: - -- `az_name` (String) Availability zone name. -- `instance_types` (List of String) Instance types in this node group. -- `name` (String) Name of node group. - - ### Nested Schema for `custom_taints`