Skip to content

Commit f36e8d8

Browse files
authored
Merge pull request #5275 from RadekManak/efa-support
✨ Implement support for EFA interface type
2 parents dcea94f + 1f2732f commit f36e8d8

11 files changed

+190
-5
lines changed

api/v1beta1/awscluster_conversion.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
5959
dst.Status.Bastion.PlacementGroupPartition = restored.Status.Bastion.PlacementGroupPartition
6060
dst.Status.Bastion.PrivateDNSName = restored.Status.Bastion.PrivateDNSName
6161
dst.Status.Bastion.PublicIPOnLaunch = restored.Status.Bastion.PublicIPOnLaunch
62+
dst.Status.Bastion.NetworkInterfaceType = restored.Status.Bastion.NetworkInterfaceType
6263
dst.Status.Bastion.CapacityReservationID = restored.Status.Bastion.CapacityReservationID
6364
dst.Status.Bastion.MarketType = restored.Status.Bastion.MarketType
6465
}

api/v1beta1/awsmachine_conversion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func (src *AWSMachine) ConvertTo(dstRaw conversion.Hub) error {
4343
dst.Spec.SecurityGroupOverrides = restored.Spec.SecurityGroupOverrides
4444
dst.Spec.CapacityReservationID = restored.Spec.CapacityReservationID
4545
dst.Spec.MarketType = restored.Spec.MarketType
46+
dst.Spec.NetworkInterfaceType = restored.Spec.NetworkInterfaceType
4647
if restored.Spec.ElasticIPPool != nil {
4748
if dst.Spec.ElasticIPPool == nil {
4849
dst.Spec.ElasticIPPool = &infrav1.ElasticIPPool{}
@@ -106,6 +107,7 @@ func (r *AWSMachineTemplate) ConvertTo(dstRaw conversion.Hub) error {
106107
dst.Spec.Template.Spec.SecurityGroupOverrides = restored.Spec.Template.Spec.SecurityGroupOverrides
107108
dst.Spec.Template.Spec.CapacityReservationID = restored.Spec.Template.Spec.CapacityReservationID
108109
dst.Spec.Template.Spec.MarketType = restored.Spec.Template.Spec.MarketType
110+
dst.Spec.Template.Spec.NetworkInterfaceType = restored.Spec.Template.Spec.NetworkInterfaceType
109111
if restored.Spec.Template.Spec.ElasticIPPool != nil {
110112
if dst.Spec.Template.Spec.ElasticIPPool == nil {
111113
dst.Spec.Template.Spec.ElasticIPPool = &infrav1.ElasticIPPool{}

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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ const (
5454
IgnitionStorageTypeOptionUnencryptedUserData = IgnitionStorageTypeOption("UnencryptedUserData")
5555
)
5656

57+
// NetworkInterfaceType is the type of network interface.
58+
type NetworkInterfaceType string
59+
60+
const (
61+
// NetworkInterfaceTypeENI means the network interface type is Elastic Network Interface.
62+
NetworkInterfaceTypeENI NetworkInterfaceType = NetworkInterfaceType("interface")
63+
// NetworkInterfaceTypeEFAWithENAInterface means the network interface type is Elastic Fabric Adapter with Elastic Network Adapter.
64+
NetworkInterfaceTypeEFAWithENAInterface NetworkInterfaceType = NetworkInterfaceType("efa")
65+
)
66+
5767
// AWSMachineSpec defines the desired state of an Amazon EC2 instance.
5868
type AWSMachineSpec struct {
5969
// ProviderID is the unique identifier as specified by the cloud provider.
@@ -153,6 +163,12 @@ type AWSMachineSpec struct {
153163
// +kubebuilder:validation:MaxItems=2
154164
NetworkInterfaces []string `json:"networkInterfaces,omitempty"`
155165

166+
// NetworkInterfaceType is the interface type of the primary network Interface.
167+
// If not specified, AWS applies a default value.
168+
// +kubebuilder:validation:Enum=interface;efa
169+
// +optional
170+
NetworkInterfaceType NetworkInterfaceType `json:"networkInterfaceType,omitempty"`
171+
156172
// UncompressedUserData specify whether the user data is gzip-compressed before it is sent to ec2 instance.
157173
// cloud-init has built-in support for gzip-compressed user data
158174
// user data stored in aws secret manager is always gzip-compressed.

api/v1beta2/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ type Instance struct {
217217
// Specifies ENIs attached to instance
218218
NetworkInterfaces []string `json:"networkInterfaces,omitempty"`
219219

220+
// NetworkInterfaceType is the interface type of the primary network Interface.
221+
NetworkInterfaceType NetworkInterfaceType `json:"networkInterfaceType,omitempty"`
222+
220223
// The tags associated with the instance.
221224
Tags map[string]string `json:"tags,omitempty"`
222225

config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,10 @@ spec:
12231223
- Spot
12241224
- CapacityBlock
12251225
type: string
1226+
networkInterfaceType:
1227+
description: NetworkInterfaceType is the interface type of the
1228+
primary network Interface.
1229+
type: string
12261230
networkInterfaces:
12271231
description: Specifies ENIs attached to instance
12281232
items:
@@ -3276,6 +3280,10 @@ spec:
32763280
- Spot
32773281
- CapacityBlock
32783282
type: string
3283+
networkInterfaceType:
3284+
description: NetworkInterfaceType is the interface type of the
3285+
primary network Interface.
3286+
type: string
32793287
networkInterfaces:
32803288
description: Specifies ENIs attached to instance
32813289
items:

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,6 +2190,10 @@ spec:
21902190
- Spot
21912191
- CapacityBlock
21922192
type: string
2193+
networkInterfaceType:
2194+
description: NetworkInterfaceType is the interface type of the
2195+
primary network Interface.
2196+
type: string
21932197
networkInterfaces:
21942198
description: Specifies ENIs attached to instance
21952199
items:

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,14 @@ spec:
891891
- Spot
892892
- CapacityBlock
893893
type: string
894+
networkInterfaceType:
895+
description: |-
896+
NetworkInterfaceType is the interface type of the primary network Interface.
897+
If not specified, AWS applies a default value.
898+
enum:
899+
- interface
900+
- efa
901+
type: string
894902
networkInterfaces:
895903
description: |-
896904
NetworkInterfaces is a list of ENIs to associate with the instance.

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,14 @@ spec:
825825
- Spot
826826
- CapacityBlock
827827
type: string
828+
networkInterfaceType:
829+
description: |-
830+
NetworkInterfaceType is the interface type of the primary network Interface.
831+
If not specified, AWS applies a default value.
832+
enum:
833+
- interface
834+
- efa
835+
type: string
828836
networkInterfaces:
829837
description: |-
830838
NetworkInterfaces is a list of ENIs to associate with the instance.

pkg/cloud/services/ec2/instances.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,12 @@ func (s *Service) CreateInstance(scope *scope.MachineScope, userData []byte, use
113113
s.scope.Debug("Creating an instance for a machine")
114114

115115
input := &infrav1.Instance{
116-
Type: scope.AWSMachine.Spec.InstanceType,
117-
IAMProfile: scope.AWSMachine.Spec.IAMInstanceProfile,
118-
RootVolume: scope.AWSMachine.Spec.RootVolume.DeepCopy(),
119-
NonRootVolumes: scope.AWSMachine.Spec.NonRootVolumes,
120-
NetworkInterfaces: scope.AWSMachine.Spec.NetworkInterfaces,
116+
Type: scope.AWSMachine.Spec.InstanceType,
117+
IAMProfile: scope.AWSMachine.Spec.IAMInstanceProfile,
118+
RootVolume: scope.AWSMachine.Spec.RootVolume.DeepCopy(),
119+
NonRootVolumes: scope.AWSMachine.Spec.NonRootVolumes,
120+
NetworkInterfaces: scope.AWSMachine.Spec.NetworkInterfaces,
121+
NetworkInterfaceType: scope.AWSMachine.Spec.NetworkInterfaceType,
121122
}
122123

123124
// Make sure to use the MachineScope here to get the merger of AWSCluster and AWSMachine tags
@@ -584,6 +585,10 @@ func (s *Service) runInstance(role string, i *infrav1.Instance) (*infrav1.Instan
584585
}
585586
}
586587

588+
if i.NetworkInterfaceType != "" {
589+
input.NetworkInterfaces[0].InterfaceType = aws.String(string(i.NetworkInterfaceType))
590+
}
591+
587592
if i.IAMProfile != "" {
588593
input.IamInstanceProfile = &ec2.IamInstanceProfileSpecification{
589594
Name: aws.String(i.IAMProfile),

pkg/cloud/services/ec2/instances_test.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,6 +2450,134 @@ func TestCreateInstance(t *testing.T) {
24502450
}
24512451
},
24522452
},
2453+
{
2454+
name: "efa interface type",
2455+
machine: &clusterv1.Machine{
2456+
ObjectMeta: metav1.ObjectMeta{
2457+
Labels: map[string]string{"set": "node"},
2458+
},
2459+
Spec: clusterv1.MachineSpec{
2460+
Bootstrap: clusterv1.Bootstrap{
2461+
DataSecretName: ptr.To[string]("bootstrap-data"),
2462+
},
2463+
},
2464+
},
2465+
machineConfig: &infrav1.AWSMachineSpec{
2466+
AMI: infrav1.AMIReference{
2467+
ID: aws.String("abc"),
2468+
},
2469+
InstanceType: "m5.large",
2470+
NetworkInterfaceType: infrav1.NetworkInterfaceTypeEFAWithENAInterface,
2471+
},
2472+
awsCluster: &infrav1.AWSCluster{
2473+
ObjectMeta: metav1.ObjectMeta{Name: "test"},
2474+
Spec: infrav1.AWSClusterSpec{
2475+
NetworkSpec: infrav1.NetworkSpec{
2476+
Subnets: infrav1.Subnets{
2477+
infrav1.SubnetSpec{
2478+
ID: "subnet-1",
2479+
IsPublic: false,
2480+
},
2481+
infrav1.SubnetSpec{
2482+
IsPublic: false,
2483+
},
2484+
},
2485+
VPC: infrav1.VPCSpec{
2486+
ID: "vpc-test",
2487+
},
2488+
},
2489+
},
2490+
Status: infrav1.AWSClusterStatus{
2491+
Network: infrav1.NetworkStatus{
2492+
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
2493+
infrav1.SecurityGroupControlPlane: {
2494+
ID: "1",
2495+
},
2496+
infrav1.SecurityGroupNode: {
2497+
ID: "2",
2498+
},
2499+
infrav1.SecurityGroupLB: {
2500+
ID: "3",
2501+
},
2502+
},
2503+
APIServerELB: infrav1.LoadBalancer{
2504+
DNSName: "test-apiserver.us-east-1.aws",
2505+
},
2506+
},
2507+
},
2508+
},
2509+
expect: func(m *mocks.MockEC2APIMockRecorder) {
2510+
m.
2511+
DescribeInstanceTypesWithContext(context.TODO(), gomock.Eq(&ec2.DescribeInstanceTypesInput{
2512+
InstanceTypes: []*string{
2513+
aws.String("m5.large"),
2514+
},
2515+
})).
2516+
Return(&ec2.DescribeInstanceTypesOutput{
2517+
InstanceTypes: []*ec2.InstanceTypeInfo{
2518+
{
2519+
ProcessorInfo: &ec2.ProcessorInfo{
2520+
SupportedArchitectures: []*string{
2521+
aws.String("x86_64"),
2522+
},
2523+
},
2524+
},
2525+
},
2526+
}, nil)
2527+
m.
2528+
RunInstancesWithContext(context.TODO(), gomock.Any()).
2529+
Do(func(_ context.Context, in *ec2.RunInstancesInput, _ ...request.Option) {
2530+
if len(in.NetworkInterfaces) == 0 {
2531+
t.Fatalf("expected a NetworkInterface to be defined")
2532+
}
2533+
if in.NetworkInterfaces[0].Groups == nil {
2534+
t.Fatalf("expected security groups to be set")
2535+
}
2536+
if interfaceType := aws.StringValue(in.NetworkInterfaces[0].InterfaceType); interfaceType != "efa" {
2537+
t.Fatalf("expected interface type to be \"efa\": got %q", interfaceType)
2538+
}
2539+
}).
2540+
Return(&ec2.Reservation{
2541+
Instances: []*ec2.Instance{
2542+
{
2543+
State: &ec2.InstanceState{
2544+
Name: aws.String(ec2.InstanceStateNamePending),
2545+
},
2546+
IamInstanceProfile: &ec2.IamInstanceProfile{
2547+
Arn: aws.String("arn:aws:iam::123456789012:instance-profile/foo"),
2548+
},
2549+
InstanceId: aws.String("two"),
2550+
InstanceType: aws.String("m5.large"),
2551+
SubnetId: aws.String("subnet-1"),
2552+
ImageId: aws.String("ami-1"),
2553+
RootDeviceName: aws.String("device-1"),
2554+
BlockDeviceMappings: []*ec2.InstanceBlockDeviceMapping{
2555+
{
2556+
DeviceName: aws.String("device-1"),
2557+
Ebs: &ec2.EbsInstanceBlockDevice{
2558+
VolumeId: aws.String("volume-1"),
2559+
},
2560+
},
2561+
},
2562+
Placement: &ec2.Placement{
2563+
AvailabilityZone: &az,
2564+
},
2565+
},
2566+
},
2567+
}, nil)
2568+
m.
2569+
DescribeNetworkInterfacesWithContext(context.TODO(), gomock.Any()).
2570+
Return(&ec2.DescribeNetworkInterfacesOutput{
2571+
NetworkInterfaces: []*ec2.NetworkInterface{},
2572+
NextToken: nil,
2573+
}, nil)
2574+
},
2575+
check: func(instance *infrav1.Instance, err error) {
2576+
if err != nil {
2577+
t.Fatalf("did not expect error: %v", err)
2578+
}
2579+
},
2580+
},
24532581
{
24542582
name: "public IP true and private subnet ID given",
24552583
machine: &clusterv1.Machine{

0 commit comments

Comments
 (0)