Skip to content

Commit

Permalink
limits api pkg (#2528)
Browse files Browse the repository at this point in the history
  • Loading branch information
jchen6585 authored Sep 1, 2023
1 parent b5c6169 commit f9a074c
Show file tree
Hide file tree
Showing 6 changed files with 363 additions and 58 deletions.
68 changes: 27 additions & 41 deletions pkg/awsutils/awsutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/aws/amazon-vpc-cni-k8s/pkg/utils/eventrecorder"
"github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger"
"github.com/aws/amazon-vpc-cni-k8s/pkg/utils/retry"
"github.com/aws/amazon-vpc-cni-k8s/pkg/vpc"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
Expand Down Expand Up @@ -277,23 +278,6 @@ type ENIMetadata struct {
IPv6Prefixes []*ec2.Ipv6PrefixSpecification
}

type NetworkCard struct {
// max number of interfaces supported per card
MaximumNetworkInterfaces int64
// the index of current card
NetworkCardIndex int64
}

// InstanceTypeLimits keeps track of limits for an instance type
type InstanceTypeLimits struct {
ENILimit int
IPv4Limit int
NetworkCards []NetworkCard
HypervisorType string
IsBareMetal bool
DefaultNetworkCardIndex int
}

// PrimaryIPv4Address returns the primary IPv4 address of this node
func (eni ENIMetadata) PrimaryIPv4Address() string {
for _, addr := range eni.IPv4Addresses {
Expand Down Expand Up @@ -1399,13 +1383,12 @@ func (cache *EC2InstanceMetadataCache) AllocIPAddress(eniID string) error {
}

func (cache *EC2InstanceMetadataCache) FetchInstanceTypeLimits() error {
_, ok := InstanceNetworkingLimits[cache.instanceType]
_, ok := vpc.GetInstance(cache.instanceType)
if ok {
return nil
}

log.Debugf("Instance type limits are missing from vpc_ip_limits.go hence making an EC2 call to fetch the limits")
var eniLimits InstanceTypeLimits
describeInstanceTypesInput := &ec2.DescribeInstanceTypesInput{InstanceTypes: []*string{aws.String(cache.instanceType)}}
output, err := cache.ec2SVC.DescribeInstanceTypesWithContext(context.Background(), describeInstanceTypesInput)
ec2ApiReq.WithLabelValues("DescribeInstanceTypes").Inc()
Expand All @@ -1424,26 +1407,17 @@ func (cache *EC2InstanceMetadataCache) FetchInstanceTypeLimits() error {
if hypervisorType == "" {
hypervisorType = "unknown"
}
networkCards := make([]NetworkCard, aws.Int64Value(info.NetworkInfo.MaximumNetworkCards))
networkCards := make([]vpc.NetworkCard, aws.Int64Value(info.NetworkInfo.MaximumNetworkCards))
defaultNetworkCardIndex := int(aws.Int64Value(info.NetworkInfo.DefaultNetworkCardIndex))
for idx := 0; idx < len(networkCards); idx += 1 {
networkCards[idx] = NetworkCard{
networkCards[idx] = vpc.NetworkCard{
MaximumNetworkInterfaces: *info.NetworkInfo.NetworkCards[idx].MaximumNetworkInterfaces,
NetworkCardIndex: *info.NetworkInfo.NetworkCards[idx].NetworkCardIndex,
}
}
//Not checking for empty hypervisorType since have seen certain instances not getting this filled.
if instanceType != "" && eniLimit > 0 && ipv4Limit > 0 {
eniLimits = InstanceTypeLimits{
ENILimit: eniLimit,
IPv4Limit: ipv4Limit,
NetworkCards: networkCards,
DefaultNetworkCardIndex: defaultNetworkCardIndex,
HypervisorType: hypervisorType,
IsBareMetal: isBareMetalInstance,
}

InstanceNetworkingLimits[instanceType] = eniLimits
vpc.SetInstance(instanceType, eniLimit, ipv4Limit, defaultNetworkCardIndex, networkCards, hypervisorType, isBareMetalInstance)
} else {
return errors.New(fmt.Sprintf("%s: %s", UnknownInstanceType, cache.instanceType))
}
Expand All @@ -1452,29 +1426,41 @@ func (cache *EC2InstanceMetadataCache) FetchInstanceTypeLimits() error {

// GetENIIPv4Limit return IP address limit per ENI based on EC2 instance type
func (cache *EC2InstanceMetadataCache) GetENIIPv4Limit() int {
eniLimits, _ := InstanceNetworkingLimits[cache.instanceType]
ipv4Limit, err := vpc.GetIPv4Limit(cache.instanceType)
if err != nil {
return -1
}
// Subtract one from the IPv4Limit since we don't use the primary IP on each ENI for pods.
return eniLimits.IPv4Limit - 1
return ipv4Limit - 1
}

// GetENILimit returns the number of ENIs can be attached to an instance
func (cache *EC2InstanceMetadataCache) GetENILimit() int {
eniLimits, _ := InstanceNetworkingLimits[cache.instanceType]
return eniLimits.ENILimit
eniLimit, err := vpc.GetENILimit(cache.instanceType)
if err != nil {
return -1
}
return eniLimit
}

// GetInstanceHypervisorFamily returns hypervisor of EC2 instance type
func (cache *EC2InstanceMetadataCache) GetInstanceHypervisorFamily() string {
eniLimits, _ := InstanceNetworkingLimits[cache.instanceType]
log.Debugf("Instance hypervisor family %s", eniLimits.HypervisorType)
return eniLimits.HypervisorType
hypervisor, err := vpc.GetHypervisorType(cache.instanceType)
if err != nil {
return ""
}
log.Debugf("Instance hypervisor family %s", hypervisor)
return hypervisor
}

// IsInstanceBareMetal derives bare metal value of the instance
func (cache *EC2InstanceMetadataCache) IsInstanceBareMetal() bool {
instanceProperties, _ := InstanceNetworkingLimits[cache.instanceType]
log.Debugf("Bare Metal Instance %s", instanceProperties.IsBareMetal)
return instanceProperties.IsBareMetal
isBaremetal, err := vpc.GetIsBareMetal(cache.instanceType)
if err != nil {
return false
}
log.Debugf("Bare Metal Instance %s", isBaremetal)
return isBaremetal
}

// GetInstanceType return EC2 instance type
Expand Down
125 changes: 125 additions & 0 deletions pkg/vpc/vpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package vpc

import (
"errors"

"github.com/aws/amazon-vpc-cni-k8s/pkg/utils/logger"
)

type NetworkCard struct {
// max number of interfaces supported per card
MaximumNetworkInterfaces int64
// the index of current card
NetworkCardIndex int64
NetworkPerformance string
}

// InstanceTypeLimits keeps track of limits for an instance type
type InstanceTypeLimits struct {
ENILimit int
IPv4Limit int
DefaultNetworkCardIndex int
NetworkCards []NetworkCard
HypervisorType string
IsBareMetal bool
}

var ErrInstanceTypeNotExist = errors.New("instance type does not exist")
var ErrNoInfo = errors.New("no info on instance type due to not being publicly available")

var log = logger.Get()

func New(eniLimit int, ipv4Limit int, defaultNetworkCardIndex int, networkCards []NetworkCard,
hypervisorType string, isBareMetalInstance bool) InstanceTypeLimits {
return InstanceTypeLimits{
ENILimit: eniLimit,
IPv4Limit: ipv4Limit,
NetworkCards: networkCards,
HypervisorType: hypervisorType,
IsBareMetal: isBareMetalInstance,
DefaultNetworkCardIndex: defaultNetworkCardIndex,
}
}

func GetENILimit(instanceType string) (int, error) {
instance, ok := GetInstance(instanceType)
if !ok {
log.Errorf("%s: %s", instanceType, ErrInstanceTypeNotExist)
return -1, ErrInstanceTypeNotExist
}
return instance.ENILimit, nil
}

func GetIPv4Limit(instanceType string) (int, error) {
instance, ok := GetInstance(instanceType)
if !ok {
log.Errorf("%s: %s", instanceType, ErrInstanceTypeNotExist)
return -1, ErrInstanceTypeNotExist
}
return instance.IPv4Limit, nil
}

func GetDefaultNetworkCardIndex(instanceType string) (int, error) {
instance, ok := GetInstance(instanceType)
if !ok {
log.Errorf("%s: %s", instanceType, ErrInstanceTypeNotExist)
return -1, ErrInstanceTypeNotExist
}
return instance.DefaultNetworkCardIndex, nil
}

func GetHypervisorType(instanceType string) (string, error) {
instance, ok := GetInstance(instanceType)
if !ok {
log.Errorf("%s: %s", instanceType, ErrInstanceTypeNotExist)
return "", ErrInstanceTypeNotExist
}
return instance.HypervisorType, nil
}

func GetIsBareMetal(instanceType string) (bool, error) {
instance, ok := GetInstance(instanceType)
if !ok {
log.Errorf("%s: %s", instanceType, ErrInstanceTypeNotExist)
return false, ErrInstanceTypeNotExist
}
return instance.IsBareMetal, nil
}

func GetNetworkCards(instanceType string) ([]NetworkCard, error) {
instance, ok := GetInstance(instanceType)
if !ok {
log.Errorf("%s: %s", instanceType, ErrInstanceTypeNotExist)
return nil, ErrInstanceTypeNotExist
}
if len(instance.NetworkCards) < 1 {
log.Errorf("%s: %s", instanceType, ErrNoInfo)
return nil, ErrNoInfo
}
return instance.NetworkCards, nil
}

func GetInstance(instanceType string) (InstanceTypeLimits, bool) {
instance, ok := instanceNetworkingLimits[instanceType]
if !ok {
return InstanceTypeLimits{}, ok
}
return instance, ok
}

func SetInstance(instanceType string, eniLimit int, ipv4Limit int, defaultNetworkCardIndex int, networkCards []NetworkCard, hypervisorType string, isBareMetalInstance bool) {
instanceNetworkingLimits[instanceType] = New(eniLimit, ipv4Limit, defaultNetworkCardIndex, networkCards,
hypervisorType, isBareMetalInstance)
}

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

Loading

0 comments on commit f9a074c

Please sign in to comment.