Skip to content

Commit a94f380

Browse files
authored
feat: add AWS instance type patch (#217)
Depends on #216 Tested manually: ``` - apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 kind: AWSMachineTemplate metadata: name: aws-quick-start-control-plane-dlj45 namespace: default template: spec: iamInstanceProfile: control-plane.cluster-api-provider-aws.sigs.k8s.io instanceType: m5.2xlarge - apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 kind: AWSMachineTemplate metadata name: aws-quick-start-md-0-infra-kpc8m namespace: default spec: template: spec: iamInstanceProfile: nodes.cluster-api-provider-aws.sigs.k8s.io instanceType: m5.4xlarge ```
1 parent 8fad4c7 commit a94f380

File tree

12 files changed

+463
-3
lines changed

12 files changed

+463
-3
lines changed

api/v1alpha1/aws_node_types.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
88
type AWSNodeSpec struct {
99
// +optional
1010
IAMInstanceProfile *IAMInstanceProfile `json:"iamInstanceProfile,omitempty"`
11+
12+
// +optional
13+
InstanceType *InstanceType `json:"instanceType,omitempty"`
1114
}
1215

1316
func (AWSNodeSpec) VariableSchema() clusterv1.VariableSchema {
@@ -17,6 +20,7 @@ func (AWSNodeSpec) VariableSchema() clusterv1.VariableSchema {
1720
Type: "object",
1821
Properties: map[string]clusterv1.JSONSchemaProps{
1922
"iamInstanceProfile": IAMInstanceProfile("").VariableSchema().OpenAPIV3Schema,
23+
"instanceType": InstanceType("").VariableSchema().OpenAPIV3Schema,
2024
},
2125
},
2226
}
@@ -32,3 +36,14 @@ func (IAMInstanceProfile) VariableSchema() clusterv1.VariableSchema {
3236
},
3337
}
3438
}
39+
40+
type InstanceType string
41+
42+
func (InstanceType) VariableSchema() clusterv1.VariableSchema {
43+
return clusterv1.VariableSchema{
44+
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
45+
Type: "string",
46+
Description: "The AWS instance type to use for the cluster Machines",
47+
},
48+
}
49+
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
+++
2+
title = "Instance type"
3+
+++
4+
5+
The instance type customization allows the user to specify the profile to use for control-plane
6+
and worker Machines.
7+
8+
This customization will be available when the
9+
[provider-specific cluster configuration patch]({{< ref "..">}}) is included in the `ClusterClass`.
10+
11+
## Example
12+
13+
To specify the instance type, use the following configuration:
14+
15+
```yaml
16+
apiVersion: cluster.x-k8s.io/v1beta1
17+
kind: Cluster
18+
metadata:
19+
name: <NAME>
20+
spec:
21+
topology:
22+
variables:
23+
- name: clusterConfig
24+
value:
25+
controlPlane:
26+
aws:
27+
instanceType: m5.xlarge
28+
- name: workerConfig
29+
value:
30+
aws:
31+
instanceType: m5.2xlarge
32+
```
33+
34+
Applying this configuration will result in the following value being set:
35+
36+
- control-plane `AWSMachineTemplate`:
37+
38+
- ```yaml
39+
spec:
40+
template:
41+
spec:
42+
instanceType: m5.xlarge
43+
```
44+
45+
- worker `AWSMachineTemplate`:
46+
47+
- ```yaml
48+
spec:
49+
template:
50+
spec:
51+
instanceType: m5.2xlarge
52+
```

pkg/handlers/aws/clusterconfig/variables_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,13 @@ func TestVariableValidation(t *testing.T) {
4242
},
4343
},
4444
},
45+
capitest.VariableTestDef{
46+
Name: "specified instance type",
47+
Vals: v1alpha1.ClusterConfigSpec{
48+
ControlPlane: &v1alpha1.NodeConfigSpec{
49+
AWS: &v1alpha1.AWSNodeSpec{InstanceType: ptr.To(v1alpha1.InstanceType("m5.small"))},
50+
},
51+
},
52+
},
4553
)
4654
}

pkg/handlers/aws/mutation/iaminstanceprofile/inject_control_plane.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ import (
2727
)
2828

2929
const (
30+
// VariableName is the external patch variable name.
31+
VariableName = "iamInstanceProfile"
32+
3033
// ControlPlaneHandlerNamePatch is the name of the inject handler.
3134
ControlPlaneHandlerNamePatch = "AWSIAMInstanceProfileControlPlanePatch"
3235
)

pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ import (
3030
)
3131

3232
const (
33-
// VariableName is the external patch variable name.
34-
VariableName = "iamInstanceProfile"
35-
3633
// WorkerHandlerNamePatch is the name of the inject handler.
3734
WorkerHandlerNamePatch = "AWSIAMInstanceProfileWorkerPatch"
3835
)
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package instancetype
5+
6+
import (
7+
"context"
8+
_ "embed"
9+
10+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers"
11+
12+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
14+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
15+
ctrl "sigs.k8s.io/controller-runtime"
16+
"sigs.k8s.io/controller-runtime/pkg/client"
17+
18+
"github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1"
19+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/apis"
20+
commonhandlers "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers"
21+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation"
22+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches"
23+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches/selectors"
24+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/variables"
25+
capav1 "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
26+
awsclusterconfig "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/aws/clusterconfig"
27+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/clusterconfig"
28+
)
29+
30+
const (
31+
// VariableName is the external patch variable name.
32+
VariableName = "instanceType"
33+
34+
// WorkerHandlerNamePatch is the name of the inject handler.
35+
ControlPlaneHandlerNamePatch = "AWSInstanceTypeControlPlanePatch"
36+
)
37+
38+
type awsInstanceTypeControlPlanePatchHandler struct {
39+
variableName string
40+
variableFieldPath []string
41+
}
42+
43+
var (
44+
_ commonhandlers.Named = &awsInstanceTypeControlPlanePatchHandler{}
45+
_ mutation.GeneratePatches = &awsInstanceTypeControlPlanePatchHandler{}
46+
_ mutation.MetaMutator = &awsInstanceTypeControlPlanePatchHandler{}
47+
)
48+
49+
func NewControlPlaneMetaPatch() *awsInstanceTypeControlPlanePatchHandler {
50+
return newAWSInstanceTypeControlPlanePatchHandler(
51+
clusterconfig.MetaVariableName,
52+
clusterconfig.MetaControlPlaneConfigName,
53+
awsclusterconfig.AWSVariableName,
54+
VariableName,
55+
)
56+
}
57+
58+
func newAWSInstanceTypeControlPlanePatchHandler(
59+
variableName string,
60+
variableFieldPath ...string,
61+
) *awsInstanceTypeControlPlanePatchHandler {
62+
return &awsInstanceTypeControlPlanePatchHandler{
63+
variableName: variableName,
64+
variableFieldPath: variableFieldPath,
65+
}
66+
}
67+
68+
func (h *awsInstanceTypeControlPlanePatchHandler) Name() string {
69+
return ControlPlaneHandlerNamePatch
70+
}
71+
72+
func (h *awsInstanceTypeControlPlanePatchHandler) Mutate(
73+
ctx context.Context,
74+
obj runtime.Object,
75+
vars map[string]apiextensionsv1.JSON,
76+
holderRef runtimehooksv1.HolderReference,
77+
_ client.ObjectKey,
78+
) error {
79+
log := ctrl.LoggerFrom(ctx).WithValues(
80+
"holderRef", holderRef,
81+
)
82+
83+
instanceTypeVar, found, err := variables.Get[v1alpha1.InstanceType](
84+
vars,
85+
h.variableName,
86+
h.variableFieldPath...,
87+
)
88+
if err != nil {
89+
return err
90+
}
91+
if !found {
92+
log.V(5).Info("AWS instance type variable for control-plane not defined")
93+
return nil
94+
}
95+
96+
log = log.WithValues(
97+
"variableName",
98+
h.variableName,
99+
"variableFieldPath",
100+
h.variableFieldPath,
101+
"variableValue",
102+
instanceTypeVar,
103+
)
104+
105+
return patches.Generate(
106+
obj,
107+
vars,
108+
&holderRef,
109+
selectors.InfrastructureControlPlaneMachines(
110+
"v1beta2",
111+
"AWSMachineTemplate",
112+
),
113+
log,
114+
func(obj *capav1.AWSMachineTemplate) error {
115+
log.WithValues(
116+
"patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(),
117+
"patchedObjectName", client.ObjectKeyFromObject(obj),
118+
).Info("setting instance type in control plane AWSMachineTemplate spec")
119+
120+
obj.Spec.Template.Spec.InstanceType = string(instanceTypeVar)
121+
122+
return nil
123+
},
124+
)
125+
}
126+
127+
func (h *awsInstanceTypeControlPlanePatchHandler) GeneratePatches(
128+
ctx context.Context,
129+
req *runtimehooksv1.GeneratePatchesRequest,
130+
resp *runtimehooksv1.GeneratePatchesResponse,
131+
) {
132+
handlers.GeneratePatches(ctx, req, resp, apis.CAPADecoder(), h.Mutate)
133+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package instancetype
5+
6+
import (
7+
"context"
8+
_ "embed"
9+
10+
awsworkerconfig "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/aws/workerconfig"
11+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/workerconfig"
12+
13+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers"
14+
15+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
16+
"k8s.io/apimachinery/pkg/runtime"
17+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
18+
ctrl "sigs.k8s.io/controller-runtime"
19+
"sigs.k8s.io/controller-runtime/pkg/client"
20+
21+
"github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1"
22+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/apis"
23+
commonhandlers "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers"
24+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation"
25+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches"
26+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches/selectors"
27+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/variables"
28+
capav1 "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
29+
)
30+
31+
const (
32+
// WorkerHandlerNamePatch is the name of the inject handler.
33+
WorkerHandlerNamePatch = "AWSInstanceTypeWorkerPatch"
34+
)
35+
36+
type awsInstanceTypeWorkerPatchHandler struct {
37+
variableName string
38+
variableFieldPath []string
39+
}
40+
41+
var (
42+
_ commonhandlers.Named = &awsInstanceTypeWorkerPatchHandler{}
43+
_ mutation.GeneratePatches = &awsInstanceTypeWorkerPatchHandler{}
44+
_ mutation.MetaMutator = &awsInstanceTypeWorkerPatchHandler{}
45+
)
46+
47+
func NewWorkerMetaPatch() *awsInstanceTypeWorkerPatchHandler {
48+
return newAWSInstanceTypeWorkerPatchHandler(
49+
workerconfig.MetaVariableName,
50+
awsworkerconfig.AWSVariableName,
51+
VariableName,
52+
)
53+
}
54+
55+
func newAWSInstanceTypeWorkerPatchHandler(
56+
variableName string,
57+
variableFieldPath ...string,
58+
) *awsInstanceTypeWorkerPatchHandler {
59+
return &awsInstanceTypeWorkerPatchHandler{
60+
variableName: variableName,
61+
variableFieldPath: variableFieldPath,
62+
}
63+
}
64+
65+
func (h *awsInstanceTypeWorkerPatchHandler) Name() string {
66+
return WorkerHandlerNamePatch
67+
}
68+
69+
func (h *awsInstanceTypeWorkerPatchHandler) Mutate(
70+
ctx context.Context,
71+
obj runtime.Object,
72+
vars map[string]apiextensionsv1.JSON,
73+
holderRef runtimehooksv1.HolderReference,
74+
_ client.ObjectKey,
75+
) error {
76+
log := ctrl.LoggerFrom(ctx).WithValues(
77+
"holderRef", holderRef,
78+
)
79+
80+
instanceTypeVar, found, err := variables.Get[v1alpha1.InstanceType](
81+
vars,
82+
h.variableName,
83+
h.variableFieldPath...,
84+
)
85+
if err != nil {
86+
return err
87+
}
88+
if !found {
89+
log.V(5).Info("AWS instance type variable for worker not defined")
90+
return nil
91+
}
92+
93+
log = log.WithValues(
94+
"variableName",
95+
h.variableName,
96+
"variableFieldPath",
97+
h.variableFieldPath,
98+
"variableValue",
99+
instanceTypeVar,
100+
)
101+
102+
return patches.Generate(
103+
obj,
104+
vars,
105+
&holderRef,
106+
selectors.InfrastructureWorkerMachineTemplates(
107+
"v1beta2",
108+
"AWSMachineTemplate",
109+
),
110+
log,
111+
func(obj *capav1.AWSMachineTemplate) error {
112+
log.WithValues(
113+
"patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(),
114+
"patchedObjectName", client.ObjectKeyFromObject(obj),
115+
).Info("setting instance type in workers AWSMachineTemplate spec")
116+
117+
obj.Spec.Template.Spec.InstanceType = string(instanceTypeVar)
118+
119+
return nil
120+
},
121+
)
122+
}
123+
124+
func (h *awsInstanceTypeWorkerPatchHandler) GeneratePatches(
125+
ctx context.Context,
126+
req *runtimehooksv1.GeneratePatchesRequest,
127+
resp *runtimehooksv1.GeneratePatchesResponse,
128+
) {
129+
handlers.GeneratePatches(ctx, req, resp, apis.CAPADecoder(), h.Mutate)
130+
}

0 commit comments

Comments
 (0)