Skip to content

Commit 0fff22f

Browse files
committed
Add AWSMachine fields to control vpc placement for the instance
1 parent e10643a commit 0fff22f

8 files changed

+362
-5
lines changed

api/v1beta1/awsmachine_conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ 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
43+
dst.Spec.SecurityGroupOverrides = restored.Spec.SecurityGroupOverrides
4244

4345
return nil
4446
}
@@ -87,6 +89,8 @@ func (r *AWSMachineTemplate) ConvertTo(dstRaw conversion.Hub) error {
8789
dst.Spec.Template.Spec.InstanceMetadataOptions = restored.Spec.Template.Spec.InstanceMetadataOptions
8890
dst.Spec.Template.Spec.PlacementGroupName = restored.Spec.Template.Spec.PlacementGroupName
8991
dst.Spec.Template.Spec.PrivateDNSName = restored.Spec.Template.Spec.PrivateDNSName
92+
dst.Spec.Template.Spec.VPC = restored.Spec.Template.Spec.VPC
93+
dst.Spec.Template.Spec.SecurityGroupOverrides = restored.Spec.Template.Spec.SecurityGroupOverrides
9094

9195
return nil
9296
}

api/v1beta1/zz_generated.conversion.go

Lines changed: 2 additions & 0 deletions
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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,21 @@ 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+
112117
// Subnet is a reference to the subnet to use for this instance. If not specified,
113118
// the cluster subnet will be used.
114119
// +optional
115120
Subnet *AWSResourceReference `json:"subnet,omitempty"`
116121

122+
// SecurityGroupOverrides is an optional set of security groups to use for the node.
123+
// This is optional - if not provided security groups from the cluster will be used.
124+
// +optional
125+
SecurityGroupOverrides map[SecurityGroupRole]string `json:"securityGroupOverrides,omitempty"`
126+
117127
// SSHKeyName is the name of the ssh key to attach to the instance. Valid values are empty string (do not use SSH keys), a valid SSH key name, or omitted (use the default SSH key name)
118128
// +optional
119129
SSHKeyName *string `json:"sshKeyName,omitempty"`

api/v1beta2/zz_generated.deepcopy.go

Lines changed: 12 additions & 0 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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,13 @@ spec:
848848
required:
849849
- size
850850
type: object
851+
securityGroupOverrides:
852+
additionalProperties:
853+
type: string
854+
description: SecurityGroupOverrides is an optional set of security
855+
groups to use for the node. This is optional - if not provided security
856+
groups from the cluster will be used.
857+
type: object
851858
spotMarketOptions:
852859
description: SpotMarketOptions allows users to configure instances
853860
to be run using AWS Spot instances.
@@ -905,6 +912,36 @@ spec:
905912
built-in support for gzip-compressed user data user data stored
906913
in aws secret manager is always gzip-compressed.
907914
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
908945
required:
909946
- instanceType
910947
type: object

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,14 @@ spec:
807807
required:
808808
- size
809809
type: object
810+
securityGroupOverrides:
811+
additionalProperties:
812+
type: string
813+
description: SecurityGroupOverrides is an optional set of
814+
security groups to use for the node. This is optional -
815+
if not provided security groups from the cluster will be
816+
used.
817+
type: object
810818
spotMarketOptions:
811819
description: SpotMarketOptions allows users to configure instances
812820
to be run using AWS Spot instances.
@@ -868,6 +876,38 @@ spec:
868876
cloud-init has built-in support for gzip-compressed user
869877
data user data stored in aws secret manager is always gzip-compressed.
870878
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
871911
required:
872912
- instanceType
873913
type: object

pkg/cloud/services/ec2/instances.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,13 @@ 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+
}
4650
input := &ec2.DescribeInstancesInput{
4751
Filters: []*ec2.Filter{
48-
filter.EC2.VPC(s.scope.VPC().ID),
52+
filter.EC2.VPC(vpcID),
4953
filter.EC2.ClusterOwned(s.scope.Name()),
5054
filter.EC2.Name(scope.Name()),
5155
filter.EC2.InstanceStates(ec2.InstanceStateNamePending, ec2.InstanceStateNameRunning),
@@ -309,7 +313,11 @@ func (s *Service) findSubnet(scope *scope.MachineScope) (string, error) {
309313
filter.EC2.SubnetStates(ec2.SubnetStatePending, ec2.SubnetStateAvailable),
310314
}
311315
if !scope.IsExternallyManaged() {
312-
criteria = append(criteria, filter.EC2.VPC(s.scope.VPC().ID))
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))
313321
}
314322
if scope.AWSMachine.Spec.Subnet.ID != nil {
315323
criteria = append(criteria, &ec2.Filter{Name: aws.String("subnet-id"), Values: aws.StringSlice([]string{*scope.AWSMachine.Spec.Subnet.ID})})
@@ -395,6 +403,30 @@ func (s *Service) findSubnet(scope *scope.MachineScope) (string, error) {
395403
}
396404
}
397405

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+
398430
// getFilteredSubnets fetches subnets filtered based on the criteria passed.
399431
func (s *Service) getFilteredSubnets(criteria ...*ec2.Filter) ([]*ec2.Subnet, error) {
400432
out, err := s.EC2Client.DescribeSubnetsWithContext(context.TODO(), &ec2.DescribeSubnetsInput{Filters: criteria})
@@ -440,10 +472,15 @@ func (s *Service) GetCoreSecurityGroups(scope *scope.MachineScope) ([]string, er
440472
}
441473
ids := make([]string, 0, len(sgRoles))
442474
for _, sg := range sgRoles {
443-
if _, ok := s.scope.SecurityGroups()[sg]; !ok {
444-
return nil, awserrors.NewFailedDependency(fmt.Sprintf("%s security group not available", sg))
475+
if _, ok := scope.AWSMachine.Spec.SecurityGroupOverrides[sg]; ok {
476+
ids = append(ids, scope.AWSMachine.Spec.SecurityGroupOverrides[sg])
477+
continue
445478
}
446-
ids = append(ids, s.scope.SecurityGroups()[sg].ID)
479+
if _, ok := s.scope.SecurityGroups()[sg]; ok {
480+
ids = append(ids, s.scope.SecurityGroups()[sg].ID)
481+
continue
482+
}
483+
return nil, awserrors.NewFailedDependency(fmt.Sprintf("%s security group not available", sg))
447484
}
448485
return ids, nil
449486
}

0 commit comments

Comments
 (0)