Skip to content

Commit 18f1187

Browse files
committed
feat: AWS cluster config patch
AWS cluster config is marked as required and region is defaulted via OpenAPI definition.
1 parent 102fb19 commit 18f1187

File tree

36 files changed

+687
-94
lines changed

36 files changed

+687
-94
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@ stringData:
4545
EOF
4646
```
4747

48+
If you are using an `AWS_PROFILE` to log in use the following:
49+
50+
```shell
51+
kubectl apply --server-side -f - <<EOF
52+
apiVersion: v1
53+
kind: Secret
54+
metadata:
55+
name: "aws-quick-start-creds"
56+
namespace: capa-system
57+
stringData:
58+
AccessKeyID: $(aws configure get aws_access_key_id)
59+
SecretAccessKey: $(aws configure get aws_secret_access_key)
60+
SessionToken: $(aws configure get aws_session_token)
61+
EOF
62+
```
63+
4864
To create a cluster, update `clusterConfig` variable and run:
4965

5066
```shell
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package v1alpha1
5+
6+
import (
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
9+
10+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/variables"
11+
)
12+
13+
//+kubebuilder:object:root=true
14+
15+
// AWSClusterConfig is the Schema for the awsclusterconfigs API.
16+
type AWSClusterConfig struct {
17+
metav1.TypeMeta `json:",inline"`
18+
metav1.ObjectMeta `json:"metadata,omitempty"`
19+
20+
Spec AWSClusterConfigSpec `json:"spec,omitempty"`
21+
}
22+
23+
// AWSClusterConfigSpec defines the desired state of AWSClusterConfig.
24+
type AWSClusterConfigSpec struct {
25+
// +optional
26+
Region *Region `json:"region,omitempty"`
27+
}
28+
29+
func (AWSClusterConfigSpec) VariableSchema() clusterv1.VariableSchema {
30+
return clusterv1.VariableSchema{
31+
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
32+
Description: "AWS Cluster configuration",
33+
Type: "object",
34+
Properties: map[string]clusterv1.JSONSchemaProps{
35+
"region": Region("").VariableSchema().OpenAPIV3Schema,
36+
},
37+
Required: []string{"region"},
38+
},
39+
}
40+
}
41+
42+
type Region string
43+
44+
const (
45+
RegionAFSouth1 Region = "af-south-1"
46+
RegionAPEast1 Region = "ap-east-1"
47+
RegionAPNorthEast1 Region = "ap-northeast-1"
48+
RegionAPNorthEast2 Region = "ap-northeast-2"
49+
RegionAPNorthEast3 Region = "ap-northeast-3"
50+
RegionAPSouth1 Region = "ap-south-1"
51+
RegionAPSouth2 Region = "ap-south-2"
52+
RegionAPSouthEast1 Region = "ap-southeast-1"
53+
RegionAPSouthEast2 Region = "ap-southeast-2"
54+
RegionAPSouthEast3 Region = "ap-southeast-3"
55+
RegionAPSouthEast4 Region = "ap-southeast-4"
56+
RegionCACentral1 Region = "ca-central-1"
57+
RegionEUCentral1 Region = "eu-central-1"
58+
RegionEUCentral2 Region = "eu-central-2"
59+
RegionEUNorth1 Region = "eu-north-1"
60+
RegionEUSouth1 Region = "eu-south-1"
61+
RegionEUSouth2 Region = "eu-south-2"
62+
RegionEUWest1 Region = "eu-west-1"
63+
RegionEUWest2 Region = "eu-west-2"
64+
RegionEUWest3 Region = "eu-west-3"
65+
RegionILCentral1 Region = "il-central-1"
66+
RegionMECentral1 Region = "me-central-1"
67+
RegionMESouth1 Region = "me-south-1"
68+
RegionSAEast1 Region = "sa-east-1"
69+
RegionUSEast1 Region = "us-east-1"
70+
RegionUSEast2 Region = "us-east-2"
71+
RegionUSWest1 Region = "us-west-1"
72+
RegionUSWest2 Region = "us-west-2"
73+
)
74+
75+
func (Region) VariableSchema() clusterv1.VariableSchema {
76+
allRegions := []Region{
77+
RegionAFSouth1,
78+
RegionAPEast1,
79+
RegionAPNorthEast1,
80+
RegionAPNorthEast2,
81+
RegionAPNorthEast3,
82+
RegionAPSouth1,
83+
RegionAPSouth2,
84+
RegionAPSouthEast1,
85+
RegionAPSouthEast2,
86+
RegionAPSouthEast3,
87+
RegionAPSouthEast4,
88+
RegionCACentral1,
89+
RegionEUCentral1,
90+
RegionEUCentral2,
91+
RegionEUNorth1,
92+
RegionEUSouth1,
93+
RegionEUSouth2,
94+
RegionEUWest1,
95+
RegionEUWest2,
96+
RegionEUWest3,
97+
RegionILCentral1,
98+
RegionMECentral1,
99+
RegionMESouth1,
100+
RegionSAEast1,
101+
RegionUSEast1,
102+
RegionUSEast2,
103+
RegionUSWest1,
104+
RegionUSWest2,
105+
}
106+
107+
return clusterv1.VariableSchema{
108+
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
109+
Type: "string",
110+
Enum: variables.MustMarshalValuesToEnumJSON(allRegions...),
111+
Default: variables.MustMarshal(RegionUSWest2),
112+
Description: "AWS region to create cluster in",
113+
},
114+
}
115+
}
116+
117+
func init() {
118+
SchemeBuilder.Register(&AWSClusterConfig{})
119+
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/main.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import (
2727
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers"
2828
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation"
2929
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/server"
30-
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/clusterconfig"
30+
awsclusterconfig "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/aws/clusterconfig"
31+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/aws/mutation/region"
32+
genericclusterconfig "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/clusterconfig"
3133
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/lifecycle/cni/calico"
3234
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/lifecycle/nfd"
3335
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/lifecycle/servicelbgc"
@@ -117,12 +119,12 @@ func main() {
117119
}
118120

119121
// Handlers for lifecycle hooks.
120-
lifeCycleHandlers := []handlers.Named{
122+
genericLifeCycleHandlers := []handlers.Named{
121123
servicelbgc.New(mgr.GetClient()),
122124
}
123125
// Handlers that apply patches to the Cluster object and its objects.
124126
// Used by CAPI's GeneratePatches hook.
125-
patchHandlers := []handlers.Named{
127+
genericPatchHandlers := []handlers.Named{
126128
httpproxy.NewPatch(mgr.GetClient()),
127129
extraapiservercertsans.NewPatch(),
128130
auditpolicy.NewPatch(),
@@ -132,34 +134,45 @@ func main() {
132134
// Handlers used by CAPI's DiscoverVariables hook.
133135
// It's ok that this does not match patchHandlers.
134136
// Some of those handlers may always get applied and not have a corresponding variable.
135-
variableHandlers := []handlers.Named{
137+
genericVariableHandlers := []handlers.Named{
136138
httpproxy.NewVariable(),
137139
extraapiservercertsans.NewVariable(),
138140
kubernetesimagerepository.NewVariable(),
139141
}
140-
// This metaPatchHandlers combines all other patch and variable handlers under a single handler.
142+
// This genericMetaPatchHandlers combines all other patch and variable handlers under a single handler.
141143
// It allows to specify configuration under a single variable.
142-
metaPatchHandlers := []mutation.MetaMutater{
144+
genericMetaPatchHandlers := []mutation.MetaMutater{
143145
httpproxy.NewMetaPatch(mgr.GetClient()),
144146
extraapiservercertsans.NewMetaPatch(),
145147
auditpolicy.NewPatch(),
146148
kubernetesimagerepository.NewMetaPatch(),
147149
etcd.NewMetaPatch(),
148150
}
149-
metaHandlers := []handlers.Named{
151+
genericMetaHandlers := []handlers.Named{
150152
// This Calico handler relies on a variable but does not generate a patch.
151153
// Instead it creates other resources in the API.
152154
calico.NewMetaHandler(mgr.GetClient(), calicoCNIConfig),
153155
nfd.NewMetaHandler(mgr.GetClient(), nfdConfig),
154-
clusterconfig.NewVariable(),
155-
mutation.NewMetaGeneratePatchesHandler("clusterConfigPatch", metaPatchHandlers...),
156+
genericclusterconfig.NewVariable(),
157+
mutation.NewMetaGeneratePatchesHandler("clusterConfigPatch", genericMetaPatchHandlers...),
158+
}
159+
160+
// This awsMetaPatchHandlers combines all AWS patch and variable handlers under a single handler.
161+
// It allows to specify configuration under a single variable.
162+
awsMetaPatchHandlers := []mutation.MetaMutater{
163+
region.NewMetaPatch(),
164+
}
165+
awsMetaHandlers := []handlers.Named{
166+
awsclusterconfig.NewVariable(),
167+
mutation.NewMetaGeneratePatchesHandler("awsClusterConfigPatch", awsMetaPatchHandlers...),
156168
}
157169

158170
var allHandlers []handlers.Named
159-
allHandlers = append(allHandlers, lifeCycleHandlers...)
160-
allHandlers = append(allHandlers, patchHandlers...)
161-
allHandlers = append(allHandlers, variableHandlers...)
162-
allHandlers = append(allHandlers, metaHandlers...)
171+
allHandlers = append(allHandlers, genericLifeCycleHandlers...)
172+
allHandlers = append(allHandlers, genericPatchHandlers...)
173+
allHandlers = append(allHandlers, genericVariableHandlers...)
174+
allHandlers = append(allHandlers, genericMetaHandlers...)
175+
allHandlers = append(allHandlers, awsMetaHandlers...)
163176

164177
runtimeWebhookServer := server.NewServer(runtimeWebhookServerOpts, allHandlers...)
165178

common/pkg/capi/clustertopology/patches/selectors/selectors.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package selectors
55

66
import (
7+
"k8s.io/apimachinery/pkg/runtime/schema"
78
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
89
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
910
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
@@ -46,3 +47,19 @@ func AllWorkersSelector() clusterv1.PatchSelector {
4647
},
4748
}
4849
}
50+
51+
// InfrastructureCluster selector matches against infrastructure clusters.
52+
// Passing in the API version (not the API group) is required because different providers could support different API
53+
// versions. This also allows for a oatch to select multiple infrastructure versions for the same provider.
54+
func InfrastructureCluster(capiInfrastructureAPIVersion, kind string) clusterv1.PatchSelector {
55+
return clusterv1.PatchSelector{
56+
APIVersion: schema.GroupVersion{
57+
Group: "infrastructure.cluster.x-k8s.io",
58+
Version: capiInfrastructureAPIVersion,
59+
}.String(),
60+
Kind: kind,
61+
MatchResources: clusterv1.PatchSelectorMatch{
62+
InfrastructureCluster: true,
63+
},
64+
}
65+
}

common/pkg/testutils/capitest/request/items.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import (
1515
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest/serializer"
1616
)
1717

18-
// requestItem returns a GeneratePatchesRequestItem with the given variables and object.
19-
func requestItem(
20-
object any,
18+
// NewRequestItem returns a GeneratePatchesRequestItem with the given variables and object.
19+
func NewRequestItem(
20+
object runtime.Object,
2121
holderRef *runtimehooksv1.HolderReference,
2222
uid types.UID,
2323
) runtimehooksv1.GeneratePatchesRequestItem {
@@ -35,7 +35,7 @@ func requestItem(
3535
}
3636

3737
func NewKubeadmConfigTemplateRequestItem(uid types.UID) runtimehooksv1.GeneratePatchesRequestItem {
38-
return requestItem(
38+
return NewRequestItem(
3939
&bootstrapv1.KubeadmConfigTemplate{
4040
TypeMeta: metav1.TypeMeta{
4141
Kind: "KubeadmConfigTemplate",
@@ -60,7 +60,7 @@ func NewKubeadmConfigTemplateRequestItem(uid types.UID) runtimehooksv1.GenerateP
6060
func NewKubeadmControlPlaneTemplateRequestItem(
6161
uid types.UID,
6262
) runtimehooksv1.GeneratePatchesRequestItem {
63-
return requestItem(
63+
return NewRequestItem(
6464
&controlplanev1.KubeadmControlPlaneTemplate{
6565
TypeMeta: metav1.TypeMeta{
6666
Kind: "KubeadmControlPlaneTemplate",

common/pkg/testutils/capitest/serializer/tojson.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,21 @@ package serializer
66
import (
77
"bytes"
88
"encoding/json"
9+
10+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
911
)
1012

1113
func ToJSON(v any) []byte {
12-
data, err := json.Marshal(v)
14+
var (
15+
data []byte
16+
err error
17+
)
18+
if u, ok := v.(*unstructured.Unstructured); ok {
19+
data, err = u.MarshalJSON()
20+
} else {
21+
data, err = json.Marshal(v)
22+
}
23+
1324
if err != nil {
1425
panic(err)
1526
}

common/pkg/testutils/capitest/variables.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func ValidateDiscoverVariables[T mutation.DiscoverVariables](
2929
t *testing.T,
3030
variableName string,
3131
variableSchema *clusterv1.VariableSchema,
32+
variableRequired bool,
3233
handlerCreator func() T,
3334
variableTestDefs ...VariableTestDef,
3435
) {
@@ -57,7 +58,7 @@ func ValidateDiscoverVariables[T mutation.DiscoverVariables](
5758
variable := resp.Variables[0]
5859
g.Expect(variable).To(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
5960
"Name": gomega.Equal(variableName),
60-
"Required": gomega.BeFalse(),
61+
"Required": gomega.Equal(variableRequired),
6162
"Schema": gomega.Equal(*variableSchema),
6263
}))
6364

0 commit comments

Comments
 (0)