Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Associate primary network interface SG with the trunk-eni when SG is not specified in ENIConfig #221

Merged
merged 2 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 17 additions & 11 deletions pkg/aws/ec2/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ type ec2Instance struct {
currentSubnetID string
// currentSubnetCIDRBlock can either point to the Subnet CIDR block for instance subnet or subnet from ENIConfig
currentSubnetCIDRBlock string
// currentInstanceSecurityGroup can either point to the instance security group or the security group in ENIConfig
// currentInstanceSecurityGroup can either point to the primary network interface security group or the security group in ENIConfig
currentInstanceSecurityGroup []string
// subnetMask is the mask of the subnet CIDR block
subnetMask string
// deviceIndexes is the list of indexes used by the EC2 Instance
deviceIndexes []bool
// instanceSecurityGroups is the security group used by the primary network interface
instanceSecurityGroups []string
// primaryENIGroups is the security group used by the primary network interface
primaryENISecurityGroups []string
// primaryENIID is the ID of the primary network interface of the instance
primaryENIID string
// newCustomNetworkingSubnetID is the SubnetID from the ENIConfig
Expand All @@ -72,7 +72,7 @@ type EC2Instance interface {
SubnetMask() string
SubnetCidrBlock() string
PrimaryNetworkInterfaceID() string
InstanceSecurityGroup() []string
CurrentInstanceSecurityGroup() []string
SetNewCustomNetworkingSpec(subnetID string, securityGroup []string)
UpdateCurrentSubnetAndCidrBlock(helper api.EC2APIHelper) error
}
Expand Down Expand Up @@ -140,11 +140,11 @@ func (i *ec2Instance) LoadDetails(ec2APIHelper api.EC2APIHelper) error {
i.deviceIndexes[*index] = true

// Load the Security group of the primary network interface
if i.instanceSecurityGroups == nil && (nwInterface.PrivateIpAddress != nil && instance.PrivateIpAddress != nil && *nwInterface.PrivateIpAddress == *instance.PrivateIpAddress) {
if i.primaryENISecurityGroups == nil && (nwInterface.PrivateIpAddress != nil && instance.PrivateIpAddress != nil && *nwInterface.PrivateIpAddress == *instance.PrivateIpAddress) {
i.primaryENIID = *nwInterface.NetworkInterfaceId
// TODO: Group can change, should be refreshed each time we want to use this
for _, group := range nwInterface.Groups {
i.instanceSecurityGroups = append(i.instanceSecurityGroups, *group.GroupId)
i.primaryENISecurityGroups = append(i.primaryENISecurityGroups, *group.GroupId)
}
}
}
Expand Down Expand Up @@ -192,8 +192,9 @@ func (i *ec2Instance) PrimaryNetworkInterfaceID() string {
return i.primaryENIID
}

// InstanceSecurityGroup returns the instance security group of the primary network interface
func (i *ec2Instance) InstanceSecurityGroup() []string {
// CurrentInstanceSecurityGroup returns the current instance security
sushrk marked this conversation as resolved.
Show resolved Hide resolved
// (primary network interface SG or SG specified in the ENIConfig
sushrk marked this conversation as resolved.
Show resolved Hide resolved
func (i *ec2Instance) CurrentInstanceSecurityGroup() []string {
i.lock.RLock()
defer i.lock.RUnlock()

Expand Down Expand Up @@ -253,7 +254,12 @@ func (i *ec2Instance) updateCurrentSubnetAndCidrBlock(ec2APIHelper api.EC2APIHel
// Custom networking is being used on node, point the current subnet ID, CIDR block and
// instance security group to the one's present in the Custom networking spec
if i.newCustomNetworkingSubnetID != "" {
i.currentInstanceSecurityGroup = i.newCustomNetworkingSecurityGroup
if i.newCustomNetworkingSecurityGroup != nil && len(i.newCustomNetworkingSecurityGroup) > 0 {
sushrk marked this conversation as resolved.
Show resolved Hide resolved
i.currentInstanceSecurityGroup = i.newCustomNetworkingSecurityGroup
} else {
// when security groups are not specified in ENIConfig, use the primary network interface SG as per custom networking documentation
i.currentInstanceSecurityGroup = i.primaryENISecurityGroups
}
// Only get the subnet CIDR block again if the subnet ID has changed
if i.newCustomNetworkingSubnetID != i.currentSubnetID {
customSubnet, err := ec2APIHelper.GetSubnet(&i.newCustomNetworkingSubnetID)
Expand All @@ -267,11 +273,11 @@ func (i *ec2Instance) updateCurrentSubnetAndCidrBlock(ec2APIHelper api.EC2APIHel
i.currentSubnetCIDRBlock = *customSubnet.CidrBlock
}
} else {
// Custom networking in not being used, point to the instance security group and
// Custom networking in not being used, point to the primary network interface security group and
// subnet details
i.currentSubnetID = i.instanceSubnetID
i.currentSubnetCIDRBlock = i.instanceSubnetCidrBlock
i.currentInstanceSecurityGroup = i.instanceSecurityGroups
i.currentInstanceSecurityGroup = i.primaryENISecurityGroups
}

return nil
Expand Down
33 changes: 32 additions & 1 deletion pkg/aws/ec2/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestEc2Instance_LoadDetails(t *testing.T) {
assert.Equal(t, subnetCidrBlock, ec2Instance.SubnetCidrBlock())
assert.Equal(t, instanceType, ec2Instance.Type())
assert.Equal(t, []bool{true, false, true}, ec2Instance.deviceIndexes)
assert.Equal(t, []string{securityGroup1, securityGroup2}, ec2Instance.InstanceSecurityGroup())
assert.Equal(t, []string{securityGroup1, securityGroup2}, ec2Instance.CurrentInstanceSecurityGroup())
assert.Equal(t, primaryInterfaceID, ec2Instance.PrimaryNetworkInterfaceID())
}

Expand Down Expand Up @@ -332,3 +332,34 @@ func TestEc2Instance_E2E(t *testing.T) {
ec2Instance.FreeDeviceIndex(deviceIndex0)
assert.False(t, ec2Instance.deviceIndexes[deviceIndex0])
}

// Tests instance details when custom networking is incorrectly configured- missing security groups
func TestEc2Instance_LoadDetails_InvalidCustomNetworkingConfiguration(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

ec2Instance, mockEC2ApiHelper := getMockInstance(ctrl)

// Set the instance subnet ID and CIDR block
ec2Instance.instanceSubnetID = subnetID
ec2Instance.instanceSubnetCidrBlock = subnetCidrBlock

// Set the custom networking subnet ID and CIDR block
customNWSubnetID := "custom-networking"
ec2Instance.newCustomNetworkingSubnetID = customNWSubnetID
ec2Instance.newCustomNetworkingSecurityGroup = []string{}

customNWSubnetCidr := "192.2.0.0/24"
customSubnet := &ec2.Subnet{CidrBlock: &customNWSubnetCidr}

mockEC2ApiHelper.EXPECT().GetInstanceDetails(&instanceID).Return(nwInterfaces, nil)
mockEC2ApiHelper.EXPECT().GetSubnet(&subnetID).Return(subnet, nil)
mockEC2ApiHelper.EXPECT().GetSubnet(&customNWSubnetID).Return(customSubnet, nil)

err := ec2Instance.LoadDetails(mockEC2ApiHelper)
assert.NoError(t, err)
assert.Equal(t, customNWSubnetID, ec2Instance.currentSubnetID)
// Expect the primary network interface security groups when ENIConfig SG is missing
assert.Equal(t, []string{securityGroup1, securityGroup2}, ec2Instance.currentInstanceSecurityGroup)
assert.Equal(t, customNWSubnetCidr, ec2Instance.currentSubnetCIDRBlock)
}
48 changes: 42 additions & 6 deletions pkg/node/manager/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,24 @@ import (
)

var (
instanceID = "i-01234567890abcdef"
providerId = "aws:///us-west-2c/" + instanceID
eniConfigName = "eni-config-name"
subnetID = "subnet-id"
nodeName = "ip-192-168-55-73.us-west-2.compute.internal"
instanceID = "i-01234567890abcdef"
providerId = "aws:///us-west-2c/" + instanceID
eniConfigName = "eni-config-name"
subnetID = "subnet-id"
nodeName = "ip-192-168-55-73.us-west-2.compute.internal"
securityGroupId = "sg-1"

eniConfig = &v1alpha1.ENIConfig{
Spec: v1alpha1.ENIConfigSpec{
Subnet: subnetID,
SecurityGroups: []string{securityGroupId},
Subnet: subnetID,
},
}

eniConfig_empty_sg = &v1alpha1.ENIConfig{
Spec: v1alpha1.ENIConfigSpec{
SecurityGroups: []string{},
Subnet: subnetID,
},
}

Expand Down Expand Up @@ -246,6 +255,33 @@ func Test_AddNode_CustomNetworking(t *testing.T) {
assert.True(t, AreNodesEqual(mock.Manager.dataStore[nodeName], managedNode))
}

// Test adding node when custom networking is enabled but incorrect ENIConfig is defined; it should succeed
func Test_AddNode_CustomNetworking_Incorrect_ENIConfig(t *testing.T) {
sushrk marked this conversation as resolved.
Show resolved Hide resolved
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mock := NewMock(ctrl, map[string]node.Node{})

job := AsyncOperationJob{
op: Init,
nodeName: nodeName,
node: managedNode,
}

nodeWithENIConfig := v1Node.DeepCopy()
nodeWithENIConfig.Labels[config.CustomNetworkingLabel] = eniConfigName

mock.MockK8sAPI.EXPECT().GetNode(nodeName).Return(nodeWithENIConfig, nil)
mock.MockK8sAPI.EXPECT().GetENIConfig(eniConfigName).Return(eniConfig_empty_sg, nil)
mock.MockWorker.EXPECT().SubmitJob(gomock.All(NewAsyncOperationMatcher(job)))

err := mock.Manager.AddNode(nodeName)
assert.NoError(t, err)
assert.Contains(t, mock.Manager.dataStore, nodeName)
assert.True(t, AreNodesEqual(mock.Manager.dataStore[nodeName], managedNode))

}

func Test_AddNode_CustomNetworking_NoENIConfig(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
Expand Down
4 changes: 2 additions & 2 deletions pkg/provider/branch/trunk/trunk.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func (t *trunkENI) InitTrunk(instance ec2.EC2Instance, podList []v1.Pod) error {
}

trunk, err := t.ec2ApiHelper.CreateAndAttachNetworkInterface(&instanceID, aws.String(t.instance.SubnetID()),
t.instance.InstanceSecurityGroup(), nil, &freeIndex, &TrunkEniDescription, &InterfaceTypeTrunk, 0)
t.instance.CurrentInstanceSecurityGroup(), nil, &freeIndex, &TrunkEniDescription, &InterfaceTypeTrunk, 0)
if err != nil {
trunkENIOperationsErrCount.WithLabelValues("create_trunk_eni").Inc()
log.Error(err, "failed to create trunk interface")
Expand Down Expand Up @@ -311,7 +311,7 @@ func (t *trunkENI) CreateAndAssociateBranchENIs(pod *v1.Pod, securityGroups []st

// If the security group is empty use the instance security group
if securityGroups == nil || len(securityGroups) == 0 {
securityGroups = t.instance.InstanceSecurityGroup()
securityGroups = t.instance.CurrentInstanceSecurityGroup()
}

var newENIs []*ENIDetails
Expand Down
4 changes: 2 additions & 2 deletions pkg/provider/branch/trunk/trunk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ func TestTrunkENI_InitTrunk_TrunkNotExists(t *testing.T) {
freeIndex := int64(2)

mockInstance.EXPECT().InstanceID().Return(InstanceId)
mockInstance.EXPECT().InstanceSecurityGroup().Return(SecurityGroups)
mockInstance.EXPECT().CurrentInstanceSecurityGroup().Return(SecurityGroups)
mockEC2APIHelper.EXPECT().GetInstanceNetworkInterface(&InstanceId).Return([]*awsEc2.InstanceNetworkInterface{}, nil)
mockInstance.EXPECT().GetHighestUnusedDeviceIndex().Return(freeIndex, nil)
mockInstance.EXPECT().SubnetID().Return(SubnetId)
Expand Down Expand Up @@ -774,7 +774,7 @@ func TestTrunkENI_CreateAndAssociateBranchENIs_InstanceSecurityGroup(t *testing.
mockInstance.EXPECT().Type().Return(InstanceType)
mockInstance.EXPECT().SubnetID().Return(SubnetId).Times(2)
mockInstance.EXPECT().SubnetCidrBlock().Return(SubnetCidrBlock).Times(2)
mockInstance.EXPECT().InstanceSecurityGroup().Return(InstanceSecurityGroup)
mockInstance.EXPECT().CurrentInstanceSecurityGroup().Return(InstanceSecurityGroup)

mockEC2APIHelper.EXPECT().CreateNetworkInterface(&BranchEniDescription, &SubnetId, InstanceSecurityGroup,
vlan1Tag, 0, nil).Return(BranchInterface1, nil)
Expand Down
2 changes: 1 addition & 1 deletion pkg/provider/ip/eni/eni.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func (e *eniManager) CreateIPV4Address(required int, ec2APIHelper api.EC2APIHelp
want = ipLimit
}
nwInterface, err := ec2APIHelper.CreateAndAttachNetworkInterface(aws.String(e.instance.InstanceID()),
aws.String(e.instance.SubnetID()), e.instance.InstanceSecurityGroup(), nil, aws.Int64(deviceIndex),
aws.String(e.instance.SubnetID()), e.instance.CurrentInstanceSecurityGroup(), nil, aws.Int64(deviceIndex),
&ENIDescription, nil, want)
if err != nil {
// TODO: Check if any clean up is required here for linux nodes only?
Expand Down
4 changes: 2 additions & 2 deletions pkg/provider/ip/eni/eni_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ func TestEniManager_CreateIPV4Address_FromNewENI(t *testing.T) {
mockInstance.EXPECT().InstanceID().Return(instanceID).Times(2)
mockInstance.EXPECT().SubnetID().Return(subnetID).Times(2)
mockInstance.EXPECT().SubnetMask().Return(subnetMask).Times(4)
mockInstance.EXPECT().InstanceSecurityGroup().Return(instanceSG).Times(2)
mockInstance.EXPECT().CurrentInstanceSecurityGroup().Return(instanceSG).Times(2)

gomock.InOrder(
mockEc2APIHelper.EXPECT().CreateAndAttachNetworkInterface(&instanceID, &subnetID, instanceSG, nil, aws.Int64(3),
Expand Down Expand Up @@ -283,7 +283,7 @@ func TestEniManager_CreateIPV4Address_InBetweenENIFail(t *testing.T) {
mockInstance.EXPECT().GetHighestUnusedDeviceIndex().Return(int64(3), nil).Times(2)
mockInstance.EXPECT().InstanceID().Return(instanceID).Times(2)
mockInstance.EXPECT().SubnetID().Return(subnetID).Times(2)
mockInstance.EXPECT().InstanceSecurityGroup().Return(instanceSG).Times(2)
mockInstance.EXPECT().CurrentInstanceSecurityGroup().Return(instanceSG).Times(2)

gomock.InOrder(
mockEc2APIHelper.EXPECT().CreateAndAttachNetworkInterface(&instanceID, &subnetID, instanceSG, nil, aws.Int64(3),
Expand Down
2 changes: 1 addition & 1 deletion scripts/gen_mocks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/pool/mock_p
# package resource maocks
mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/resource/mock_resources.go github.com/aws/amazon-vpc-resource-controller-k8s/pkg/resource ResourceManager
# package condition maocks
mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/condition/mock_condtion.go github.com/aws/amazon-vpc-resource-controller-k8s/pkg/condition Conditions
mockgen -destination=../mocks/amazon-vcp-resource-controller-k8s/pkg/condition/mock_condition.go github.com/aws/amazon-vpc-resource-controller-k8s/pkg/condition Conditions
haouc marked this conversation as resolved.
Show resolved Hide resolved