diff --git a/pkg/cloud/metadata/ec2.go b/pkg/cloud/metadata/ec2.go index c35c3c4054..a20afd6342 100644 --- a/pkg/cloud/metadata/ec2.go +++ b/pkg/cloud/metadata/ec2.go @@ -88,7 +88,8 @@ func EC2MetadataInstanceInfo(svc EC2Metadata, regionFromSession string) (*Metada if err != nil { return nil, fmt.Errorf("could not read ENIs metadata content: %w", err) } - attachedENIs := strings.Count(string(enis), "\n") + attachedENIs := util.CountMACAddresses(string(enis)) + klog.V(4).InfoS("Number of attached ENIs", "attachedENIs", attachedENIs) blockDevMappings := 0 if !util.IsSBE(doc.Region) { diff --git a/pkg/cloud/metadata/metadata_test.go b/pkg/cloud/metadata/metadata_test.go index 7fb66ea610..d5a4914ea6 100644 --- a/pkg/cloud/metadata/metadata_test.go +++ b/pkg/cloud/metadata/metadata_test.go @@ -115,7 +115,7 @@ func TestNewMetadataService(t *testing.T) { }, }, nil) mockEC2Metadata.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: EnisEndpoint}).Return(&imds.GetMetadataOutput{ - Content: io.NopCloser(strings.NewReader("01:23:45:67:89:ab\n")), + Content: io.NopCloser(strings.NewReader("01:23:45:67:89:ab")), }, nil) mockEC2Metadata.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: BlockDevicesEndpoint}).Return(&imds.GetMetadataOutput{ Content: io.NopCloser(strings.NewReader("ebs\nebs\n")), @@ -257,7 +257,7 @@ func TestEC2MetadataInstanceInfo(t *testing.T) { }, }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: EnisEndpoint}).Return(&imds.GetMetadataOutput{ - Content: io.NopCloser(strings.NewReader("eni-1\neni-2\n")), + Content: io.NopCloser(strings.NewReader("eni-1\neni-2")), }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: BlockDevicesEndpoint}).Return(nil, errors.New("failed to get block device mappings metadata")) }, @@ -275,7 +275,7 @@ func TestEC2MetadataInstanceInfo(t *testing.T) { }, }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: EnisEndpoint}).Return(&imds.GetMetadataOutput{ - Content: io.NopCloser(strings.NewReader("eni-1\neni-2\n")), + Content: io.NopCloser(strings.NewReader("01:23:45:67:89:ab\n02:23:45:67:89:ab")), }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: BlockDevicesEndpoint}).Return(&imds.GetMetadataOutput{ Content: io.NopCloser(errReader{}), @@ -295,7 +295,7 @@ func TestEC2MetadataInstanceInfo(t *testing.T) { }, }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: EnisEndpoint}).Return(&imds.GetMetadataOutput{ - Content: io.NopCloser(strings.NewReader("eni-1\neni-2\n")), + Content: io.NopCloser(strings.NewReader("01:23:45:67:89:ab\n02:23:45:67:89:ab")), }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: BlockDevicesEndpoint}).Return(&imds.GetMetadataOutput{ Content: io.NopCloser(strings.NewReader("ebs\nebs\n")), @@ -332,7 +332,7 @@ func TestEC2MetadataInstanceInfo(t *testing.T) { }, }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: EnisEndpoint}).Return(&imds.GetMetadataOutput{ - Content: io.NopCloser(strings.NewReader("eni-1\neni-2\n")), + Content: io.NopCloser(strings.NewReader("01:23:45:67:89:ab\n02:23:45:67:89:ab")), }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: BlockDevicesEndpoint}).Return(&imds.GetMetadataOutput{ Content: io.NopCloser(strings.NewReader("ebs\nebs\n")), @@ -362,7 +362,7 @@ func TestEC2MetadataInstanceInfo(t *testing.T) { }, }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: EnisEndpoint}).Return(&imds.GetMetadataOutput{ - Content: io.NopCloser(strings.NewReader("eni-1\neni-2\n")), + Content: io.NopCloser(strings.NewReader("01:23:45:67:89:ab\n02:23:45:67:89:ab")), }, nil) m.EXPECT().GetMetadata(gomock.Any(), &imds.GetMetadataInput{Path: OutpostArnEndpoint}).Return(nil, errors.New("404 - Not Found")) }, diff --git a/pkg/util/util.go b/pkg/util/util.go index 1b6bbd734d..3e0c5a6082 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -37,6 +37,8 @@ const ( var ( isAlphanumericRegex = regexp.MustCompile(`^[a-zA-Z0-9]*$`).MatchString + // MAC Address Regex Source: https://stackoverflow.com/a/4260512 + isMACAddressRegex = regexp.MustCompile(`([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})`) ) // RoundUpBytes rounds up the volume size in bytes up to multiplications of GiB @@ -137,6 +139,12 @@ func StringIsAlphanumeric(s string) bool { return isAlphanumericRegex(s) } +// CountMACAddresses returns the amount of MAC addresses within a string +func CountMACAddresses(s string) int { + matches := isMACAddressRegex.FindAllStringIndex(s, -1) + return len(matches) +} + // NormalizeWindowsPath normalizes a Windows path func NormalizeWindowsPath(path string) string { normalizedPath := strings.Replace(path, "/", "\\", -1) diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index ecf7e22a8f..c5a71f3ca6 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -185,6 +185,46 @@ func TestIsAlphanumeric(t *testing.T) { } } +func TestCountMACAddresses(t *testing.T) { + testCases := []struct { + name string + testString string + expResult int + }{ + { + name: "success with newline at end", + testString: "0e:1c:7d:81:2b:19/\n0e:8c:22:a2:16:ef/\n", + expResult: 2, + }, + { + name: "success with no newline", + testString: "0e:1c:7d:81:2b:19/\n0e:8c:22:a2:16:ef/sh-4.2$", + expResult: 2, + }, + { + name: "success with no addresses", + testString: "00:::00/sh-4.2$", + expResult: 0, + }, + { + name: "success with hard case", + testString: "Zé:1c:7d:81:2b:19/\n23:123:22:a2:16:ef/ff\n:/:sh-4.2$", + expResult: 0, + }, + { + name: "success with carriage returns and beginning newline", + testString: "\r\n0e:1c:7d:81:2b:19/\r\n0e:8c:22:a2:16:ef/\r\n0e:8c:22:a2:16:ef/sh-4.2$", + expResult: 3, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res := CountMACAddresses(tc.testString) + assert.Equalf(t, tc.expResult, res, "Wrong value returned for CountMACAddresses. Expected %d for string %s, got %d", tc.expResult, tc.testString, res) + }) + } +} + type TestRequest struct { Name string Secrets map[string]string