Skip to content

Commit

Permalink
Support for setting MarketType/InstanceMarketOptions for use with "ca…
Browse files Browse the repository at this point in the history
…pacity-block"

Signed-off-by: Davanum Srinivas <[email protected]>
  • Loading branch information
dims committed Feb 11, 2025
1 parent a8523c9 commit e481f15
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 0 deletions.
27 changes: 27 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/assets/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,21 @@
"x-intellij-html-description": "holds any arbitrary JSON/YAML documents, such as extra config parameters or IAM policies",
"default": "{}"
},
"InstanceMarketOptions": {
"properties": {
"marketType": {
"type": "string",
"description": "specifies the market type for the instances",
"x-intellij-html-description": "specifies the market type for the instances"
}
},
"preferredOrder": [
"marketType"
],
"additionalProperties": false,
"description": "describes the market (purchasing) option for the instances",
"x-intellij-html-description": "describes the market (purchasing) option for the instances"
},
"InstanceSelector": {
"properties": {
"cpuArchitecture": {
Expand Down Expand Up @@ -1419,6 +1434,11 @@
"iam": {
"$ref": "#/definitions/NodeGroupIAM"
},
"instanceMarketOptions": {
"$ref": "#/definitions/InstanceMarketOptions",
"description": "describes the market (purchasing) option for the instances",
"x-intellij-html-description": "describes the market (purchasing) option for the instances"
},
"instanceName": {
"type": "string"
},
Expand Down Expand Up @@ -1629,6 +1649,7 @@
"bottlerocket",
"enableDetailedMonitoring",
"capacityReservation",
"instanceMarketOptions",
"outpostARN",
"instanceTypes",
"spot",
Expand Down Expand Up @@ -1792,6 +1813,11 @@
"iam": {
"$ref": "#/definitions/NodeGroupIAM"
},
"instanceMarketOptions": {
"$ref": "#/definitions/InstanceMarketOptions",
"description": "describes the market (purchasing) option for the instances",
"x-intellij-html-description": "describes the market (purchasing) option for the instances"
},
"instanceName": {
"type": "string"
},
Expand Down Expand Up @@ -1999,6 +2025,7 @@
"bottlerocket",
"enableDetailedMonitoring",
"capacityReservation",
"instanceMarketOptions",
"outpostARN",
"instancesDistribution",
"asgMetricsCollection",
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,10 @@ type NodeGroupBase struct {
// CapacityReservation defines reservation policy for a nodegroup
CapacityReservation *CapacityReservation `json:"capacityReservation,omitempty"`

// InstanceMarketOptions describes the market (purchasing) option for the instances
// +optional
InstanceMarketOptions *InstanceMarketOptions `json:"instanceMarketOptions,omitempty"`

// OutpostARN specifies the Outpost ARN in which the nodegroup should be created.
// +optional
OutpostARN string `json:"outpostARN,omitempty"`
Expand All @@ -1773,6 +1777,12 @@ type CapacityReservationTarget struct {
CapacityReservationResourceGroupARN *string `json:"capacityReservationResourceGroupARN,omitempty"`
}

// InstanceMarketOptions describes the market (purchasing) option for the instances
type InstanceMarketOptions struct {
// MarketType specifies the market type for the instances
MarketType *string `json:"marketType,omitempty"`
}

// Placement specifies placement group information
type Placement struct {
GroupName string `json:"groupName,omitempty"`
Expand Down
12 changes: 12 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,18 @@ func validateNodeGroupBase(np NodePool, path string, controlPlaneOnOutposts bool
return errors.New("only one of CapacityReservationID or CapacityReservationResourceGroupARN may be specified at a time")
}
}

if ng.InstanceMarketOptions != nil {
if ng.InstanceMarketOptions.MarketType != nil {
if *ng.InstanceMarketOptions.MarketType != "capacity-block" {
return fmt.Errorf(`only accepted value is "capacity-block"; got "%s"`, *ng.InstanceMarketOptions.MarketType)
}
}
}
} else {
if ng.InstanceMarketOptions != nil {
return errors.New("instanceMarketOptions cannot be set without capacityReservation")
}
}

return nil
Expand Down
46 changes: 46 additions & 0 deletions pkg/apis/eksctl.io/v1alpha5/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2602,6 +2602,52 @@ var _ = Describe("ClusterConfig validation", func() {
})
})

Describe("Instance Market Options validation", func() {
var (
cfg *api.ClusterConfig
ng *api.NodeGroup
)

BeforeEach(func() {
cfg = api.NewClusterConfig()
ng = cfg.NewNodeGroup()
ng.Name = "ng"
})

When("InstanceMarketOptions is set", func() {
When("it is set to 'capacity-block'", func() {
It("does not fail", func() {
ng.CapacityReservation = &api.CapacityReservation{
CapacityReservationTarget: &api.CapacityReservationTarget{
CapacityReservationID: aws.String("id"),
},
}
ng.InstanceMarketOptions = &api.InstanceMarketOptions{MarketType: aws.String("capacity-block")}
Expect(api.ValidateNodeGroup(0, ng, cfg)).To(Succeed())
})
})

When("it is set to 'capacity-block' but Capacity Reservation not set", func() {
It("does fail", func() {
ng.InstanceMarketOptions = &api.InstanceMarketOptions{MarketType: aws.String("capacity-block")}
Expect(api.ValidateNodeGroup(0, ng, cfg)).To(MatchError(ContainSubstring(`instanceMarketOptions cannot be set without capacityReservation`)))
})
})

When("it is set to 'foobar'", func() {
It("does fail", func() {
ng.CapacityReservation = &api.CapacityReservation{
CapacityReservationTarget: &api.CapacityReservationTarget{
CapacityReservationID: aws.String("id"),
},
}
ng.InstanceMarketOptions = &api.InstanceMarketOptions{MarketType: aws.String("foobar")}
Expect(api.ValidateNodeGroup(0, ng, cfg)).To(MatchError(ContainSubstring(`only accepted value is "capacity-block"; got "foobar"`)))
})
})
})
})

DescribeTable("ToPodIdentityAssociationID", func(piaARN, expectedID, expectedErr string) {
piaID, err := api.ToPodIdentityAssociationID(piaARN)
if expectedErr != "" {
Expand Down
5 changes: 5 additions & 0 deletions pkg/cfn/builder/managed_launch_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ func (m *ManagedNodeGroupResourceSet) makeLaunchTemplateData(ctx context.Context
CapacityReservationResourceGroupArn: valueOrNil(mng.CapacityReservation.CapacityReservationTarget.CapacityReservationResourceGroupARN),
}
}
if mng.InstanceMarketOptions != nil {
launchTemplateData.InstanceMarketOptions = &gfnec2.LaunchTemplate_InstanceMarketOptions{
MarketType: valueOrNil(mng.InstanceMarketOptions.MarketType),
}
}
}

userData, err := m.bootstrapper.UserData()
Expand Down
5 changes: 5 additions & 0 deletions pkg/cfn/builder/nodegroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,11 @@ func newLaunchTemplateData(ctx context.Context, n *NodeGroupResourceSet) (*gfnec
CapacityReservationResourceGroupArn: valueOrNil(ng.CapacityReservation.CapacityReservationTarget.CapacityReservationResourceGroupARN),
}
}
if ng.InstanceMarketOptions != nil {
launchTemplateData.InstanceMarketOptions = &gfnec2.LaunchTemplate_InstanceMarketOptions{
MarketType: valueOrNil(ng.InstanceMarketOptions.MarketType),
}
}
}

if err := buildNetworkInterfaces(ctx, launchTemplateData, ng.InstanceTypeList(), api.IsEnabled(ng.EFAEnabled), n.securityGroups, n.ec2API); err != nil {
Expand Down

0 comments on commit e481f15

Please sign in to comment.