Skip to content

Commit 0fa2337

Browse files
committed
Drop the VPC field from the AWSMachine spec, look up the VPC from the subnet instead
1 parent 0fff22f commit 0fa2337

10 files changed

+241
-150
lines changed

api/v1beta1/awsmachine_conversion.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ func (src *AWSMachine) ConvertTo(dstRaw conversion.Hub) error {
3939
dst.Spec.InstanceMetadataOptions = restored.Spec.InstanceMetadataOptions
4040
dst.Spec.PlacementGroupName = restored.Spec.PlacementGroupName
4141
dst.Spec.PrivateDNSName = restored.Spec.PrivateDNSName
42-
dst.Spec.VPC = restored.Spec.VPC
4342
dst.Spec.SecurityGroupOverrides = restored.Spec.SecurityGroupOverrides
4443

4544
return nil
@@ -89,7 +88,6 @@ func (r *AWSMachineTemplate) ConvertTo(dstRaw conversion.Hub) error {
8988
dst.Spec.Template.Spec.InstanceMetadataOptions = restored.Spec.Template.Spec.InstanceMetadataOptions
9089
dst.Spec.Template.Spec.PlacementGroupName = restored.Spec.Template.Spec.PlacementGroupName
9190
dst.Spec.Template.Spec.PrivateDNSName = restored.Spec.Template.Spec.PrivateDNSName
92-
dst.Spec.Template.Spec.VPC = restored.Spec.Template.Spec.VPC
9391
dst.Spec.Template.Spec.SecurityGroupOverrides = restored.Spec.Template.Spec.SecurityGroupOverrides
9492

9593
return nil

api/v1beta1/zz_generated.conversion.go

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

api/v1beta2/awsmachine_types.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,6 @@ type AWSMachineSpec struct {
109109
// +optional
110110
AdditionalSecurityGroups []AWSResourceReference `json:"additionalSecurityGroups,omitempty"`
111111

112-
// VPC is a reference to the VPC to use when picking a subnet to use for this
113-
// instance. Only valid if the subnet (id or filters) is also specified.
114-
// +optional
115-
VPC *AWSResourceReference `json:"vpc,omitempty"`
116-
117112
// Subnet is a reference to the subnet to use for this instance. If not specified,
118113
// the cluster subnet will be used.
119114
// +optional

api/v1beta2/zz_generated.deepcopy.go

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

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -912,36 +912,6 @@ spec:
912912
built-in support for gzip-compressed user data user data stored
913913
in aws secret manager is always gzip-compressed.
914914
type: boolean
915-
vpc:
916-
description: VPC is a reference to the VPC to use when picking a subnet
917-
to use for this instance. Only valid if the subnet (id or filters)
918-
is also specified.
919-
properties:
920-
filters:
921-
description: 'Filters is a set of key/value pairs used to identify
922-
a resource They are applied according to the rules defined by
923-
the AWS API: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Filtering.html'
924-
items:
925-
description: Filter is a filter used to identify an AWS resource.
926-
properties:
927-
name:
928-
description: Name of the filter. Filter names are case-sensitive.
929-
type: string
930-
values:
931-
description: Values includes one or more filter values.
932-
Filter values are case-sensitive.
933-
items:
934-
type: string
935-
type: array
936-
required:
937-
- name
938-
- values
939-
type: object
940-
type: array
941-
id:
942-
description: ID of resource
943-
type: string
944-
type: object
945915
required:
946916
- instanceType
947917
type: object

config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -876,38 +876,6 @@ spec:
876876
cloud-init has built-in support for gzip-compressed user
877877
data user data stored in aws secret manager is always gzip-compressed.
878878
type: boolean
879-
vpc:
880-
description: VPC is a reference to the VPC to use when picking
881-
a subnet to use for this instance. Only valid if the subnet
882-
(id or filters) is also specified.
883-
properties:
884-
filters:
885-
description: 'Filters is a set of key/value pairs used
886-
to identify a resource They are applied according to
887-
the rules defined by the AWS API: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Filtering.html'
888-
items:
889-
description: Filter is a filter used to identify an
890-
AWS resource.
891-
properties:
892-
name:
893-
description: Name of the filter. Filter names are
894-
case-sensitive.
895-
type: string
896-
values:
897-
description: Values includes one or more filter
898-
values. Filter values are case-sensitive.
899-
items:
900-
type: string
901-
type: array
902-
required:
903-
- name
904-
- values
905-
type: object
906-
type: array
907-
id:
908-
description: ID of resource
909-
type: string
910-
type: object
911879
required:
912880
- instanceType
913881
type: object

controllers/awsmachine_controller_test.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -530,10 +530,6 @@ func mockedCreateSecretCall(s *mock_services.MockSecretInterfaceMockRecorder) {
530530
func mockedCreateInstanceCalls(m *mocks.MockEC2APIMockRecorder) {
531531
m.DescribeInstancesWithContext(context.TODO(), gomock.Eq(&ec2.DescribeInstancesInput{
532532
Filters: []*ec2.Filter{
533-
{
534-
Name: aws.String("vpc-id"),
535-
Values: aws.StringSlice([]string{""}),
536-
},
537533
{
538534
Name: aws.String("tag:sigs.k8s.io/cluster-api-provider-aws/cluster/test-cluster"),
539535
Values: aws.StringSlice([]string{"owned"}),
@@ -642,10 +638,6 @@ func mockedCreateInstanceCalls(m *mocks.MockEC2APIMockRecorder) {
642638
Name: aws.String("state"),
643639
Values: aws.StringSlice([]string{"pending", "available"}),
644640
},
645-
{
646-
Name: aws.String("vpc-id"),
647-
Values: aws.StringSlice([]string{""}),
648-
},
649641
{
650642
Name: aws.String("subnet-id"),
651643
Values: aws.StringSlice([]string{"subnet-1"}),

docs/book/src/topics/bring-your-own-aws-infrastructure.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,30 @@ spec:
120120

121121
Users may either specify `failureDomain` on the Machine or MachineDeployment objects, _or_ users may explicitly specify subnet IDs on the AWSMachine or AWSMachineTemplate objects. If both are specified, the subnet ID is used and the `failureDomain` is ignored.
122122

123+
### Placing EC2 Instances in Specific External VPCs
124+
125+
CAPA clusters are deployed within a single VPC, but it's possible to place machines that live in external VPCs. For this kind of configuration, we assume that all the VPCs have the ability to communicate, either through external peering, a transit gateway, or some other mechanism already established outside of CAPA. CAPA will not create a tunnel or manage the network configuration for any secondary VPCs.
126+
127+
The AWSMachineTemplate `subnet` field allows specifying filters or specific subnet ids for worker machine placement. If the filters or subnet id is specified in a secondary VPC, CAPA will place the machine in that VPC and subnet.
128+
129+
```yaml
130+
spec:
131+
template:
132+
spec:
133+
subnet:
134+
filters:
135+
name: "vpc-id"
136+
values:
137+
- "secondary-vpc-id"
138+
securityGroupOverrides:
139+
node: sg-04e870a3507a5ad2c5c8c2
140+
node-eks-additional: sg-04e870a3507a5ad2c5c8c1
141+
```
142+
143+
#### Caveats/Notes
144+
145+
CAPA helpfully creates security groups for various roles in the cluster and automatically attaches them to workers. However, security groups are tied to a specific VPC, so workers placed in a VPC outside of the cluster will need to have these security groups created by some external process first and set in the `securityGroupOverrides` field, otherwise the ec2 creation will fail.
146+
123147
### Security Groups
124148

125149
To use existing security groups for instances for a cluster, add this to the AWSCluster specification:
@@ -147,6 +171,15 @@ spec:
147171
- ...
148172
```
149173

174+
It's also possible to override the cluster security groups for an individual AWSMachine or AWSMachineTemplate:
175+
176+
```yaml
177+
spec:
178+
SecurityGroupOverrides:
179+
node: sg-04e870a3507a5ad2c5c8c2
180+
node-eks-additional: sg-04e870a3507a5ad2c5c8c1
181+
```
182+
150183
### Control Plane Load Balancer
151184

152185
The cluster control plane is accessed through a Classic ELB. By default, Cluster API creates the Classic ELB. To use an existing Classic ELB, add its name to the AWSCluster specification:

pkg/cloud/services/ec2/instances.go

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,8 @@ import (
4343
func (s *Service) GetRunningInstanceByTags(scope *scope.MachineScope) (*infrav1.Instance, error) {
4444
s.scope.Debug("Looking for existing machine instance by tags")
4545

46-
vpcID, err := s.getVPCID(scope)
47-
if err != nil {
48-
return nil, err
49-
}
5046
input := &ec2.DescribeInstancesInput{
5147
Filters: []*ec2.Filter{
52-
filter.EC2.VPC(vpcID),
5348
filter.EC2.ClusterOwned(s.scope.Name()),
5449
filter.EC2.Name(scope.Name()),
5550
filter.EC2.InstanceStates(ec2.InstanceStateNamePending, ec2.InstanceStateNameRunning),
@@ -312,13 +307,6 @@ func (s *Service) findSubnet(scope *scope.MachineScope) (string, error) {
312307
criteria := []*ec2.Filter{
313308
filter.EC2.SubnetStates(ec2.SubnetStatePending, ec2.SubnetStateAvailable),
314309
}
315-
if !scope.IsExternallyManaged() {
316-
vpcID, err := s.getVPCID(scope)
317-
if err != nil {
318-
return "", fmt.Errorf("failed to lookup vpc for subnets: %w", err)
319-
}
320-
criteria = append(criteria, filter.EC2.VPC(vpcID))
321-
}
322310
if scope.AWSMachine.Spec.Subnet.ID != nil {
323311
criteria = append(criteria, &ec2.Filter{Name: aws.String("subnet-id"), Values: aws.StringSlice([]string{*scope.AWSMachine.Spec.Subnet.ID})})
324312
}
@@ -353,6 +341,11 @@ func (s *Service) findSubnet(scope *scope.MachineScope) (string, error) {
353341
}
354342
filtered = append(filtered, subnet)
355343
}
344+
// prefer a subnet in the cluster VPC if multiple match
345+
clusterVPC := s.scope.VPC().ID
346+
sort.SliceStable(filtered, func(i, j int) bool {
347+
return strings.Compare(*filtered[i].VpcId, clusterVPC) > strings.Compare(*filtered[j].VpcId, clusterVPC)
348+
})
356349
if len(filtered) == 0 {
357350
errMessage = fmt.Sprintf("failed to run machine %q, found %d subnets matching criteria but post-filtering failed.",
358351
scope.Name(), len(subnets)) + errMessage
@@ -403,30 +396,6 @@ func (s *Service) findSubnet(scope *scope.MachineScope) (string, error) {
403396
}
404397
}
405398

406-
func (s *Service) getVPCID(scope *scope.MachineScope) (string, error) {
407-
if scope.AWSMachine.Spec.VPC == nil {
408-
return s.scope.VPC().ID, nil
409-
}
410-
if scope.AWSMachine.Spec.VPC.ID != nil {
411-
return *scope.AWSMachine.Spec.VPC.ID, nil
412-
}
413-
filters := make([]*ec2.Filter, 0, len(scope.AWSMachine.Spec.VPC.Filters))
414-
for _, filter := range scope.AWSMachine.Spec.VPC.Filters {
415-
filters = append(filters, &ec2.Filter{
416-
Name: aws.String(filter.Name),
417-
Values: aws.StringSlice(filter.Values),
418-
})
419-
}
420-
out, err := s.EC2Client.DescribeVpcsWithContext(context.TODO(), &ec2.DescribeVpcsInput{Filters: filters})
421-
if err != nil {
422-
return "", err
423-
}
424-
if out != nil && len(out.Vpcs) == 1 {
425-
return *out.Vpcs[0].VpcId, nil
426-
}
427-
return "", fmt.Errorf("ambigious VPC filters, only one VPC expected, got %v", out)
428-
}
429-
430399
// getFilteredSubnets fetches subnets filtered based on the criteria passed.
431400
func (s *Service) getFilteredSubnets(criteria ...*ec2.Filter) ([]*ec2.Subnet, error) {
432401
out, err := s.EC2Client.DescribeSubnetsWithContext(context.TODO(), &ec2.DescribeSubnetsInput{Filters: criteria})

0 commit comments

Comments
 (0)