Skip to content

Commit

Permalink
Add Windows secondary IP mode configurable options for managing IP ad…
Browse files Browse the repository at this point in the history
…dress allocation aws#443
  • Loading branch information
tzifudzi committed Jul 17, 2024
1 parent 020d23a commit ba0f44a
Show file tree
Hide file tree
Showing 15 changed files with 821 additions and 154 deletions.
41 changes: 27 additions & 14 deletions controllers/core/configmap_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ type ConfigMapReconciler struct {
Condition condition.Conditions
curWinIPAMEnabledCond bool
curWinPrefixDelegationEnabledCond bool
curWinPDWarmIPTarget int
curWinPDMinIPTarget int
curWinWarmIPTarget int
curWinMinIPTarget int
curWinPDWarmPrefixTarget int
Context context.Context
}
Expand Down Expand Up @@ -116,21 +116,34 @@ func (r *ConfigMapReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
isPrefixFlagUpdated = true
}

// Check if configurations for Windows prefix delegation have changed
var isPDConfigUpdated bool
warmIPTarget, minIPTarget, warmPrefixTarget := config.ParseWinPDTargets(r.Log, configmap)
if r.curWinPDWarmIPTarget != warmIPTarget || r.curWinPDMinIPTarget != minIPTarget || r.curWinPDWarmPrefixTarget != warmPrefixTarget {
r.curWinPDWarmIPTarget = warmIPTarget
r.curWinPDMinIPTarget = minIPTarget
r.curWinPDWarmPrefixTarget = warmPrefixTarget
logger.Info("updated PD configs from configmap", config.WarmIPTarget, r.curWinPDWarmIPTarget,
config.MinimumIPTarget, r.curWinPDMinIPTarget, config.WarmPrefixTarget, r.curWinPDWarmPrefixTarget)
// Check if Windows IP target configurations in ConfigMap have changed
var isWinIPConfigsUpdated bool

isPDConfigUpdated = true
warmIPTarget, minIPTarget, warmPrefixTarget, isPDEnabled := config.ParseWinIPTargetConfigs(r.Log, configmap)
var winMinIPTargetUpdated = r.curWinMinIPTarget != minIPTarget
var winWarmIPTargetUpdated = r.curWinWarmIPTarget != warmIPTarget
var winPDWarmPrefixTargetUpdated = r.curWinPDWarmPrefixTarget != warmPrefixTarget
if winWarmIPTargetUpdated || winMinIPTargetUpdated {
r.curWinWarmIPTarget = warmIPTarget
r.curWinMinIPTarget = minIPTarget
r.curWinPDWarmPrefixTarget = warmPrefixTarget
isWinIPConfigsUpdated = true
}
if isPDEnabled && winPDWarmPrefixTargetUpdated {
isWinIPConfigsUpdated = true
}
if isWinIPConfigsUpdated {
logger.Info(
"Detected update in Windows IP configuration parameter values in ConfigMap",
config.WinWarmIPTarget, r.curWinWarmIPTarget,
config.WinMinimumIPTarget, r.curWinMinIPTarget,
config.WinWarmPrefixTarget, r.curWinPDWarmPrefixTarget,
config.EnableWindowsPrefixDelegationKey, isPDEnabled,
)
}

// Flag is updated, update all nodes
if isIPAMFlagUpdated || isPrefixFlagUpdated || isPDConfigUpdated {
var nodesRequireUpdate = isIPAMFlagUpdated || isPrefixFlagUpdated || isWinIPConfigsUpdated
if nodesRequireUpdate {
err := UpdateNodesOnConfigMapChanges(r.K8sAPI, r.NodeManager)
if err != nil {
// Error in updating nodes
Expand Down
40 changes: 27 additions & 13 deletions controllers/core/configmap_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,9 @@ package controllers
import (
"context"
"errors"
"strconv"
"testing"

mock_condition "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/condition"
mock_k8s "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/k8s"
mock_node "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/node"
mock_manager "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/node/manager"
"github.com/aws/amazon-vpc-resource-controller-k8s/pkg/config"
cooldown "github.com/aws/amazon-vpc-resource-controller-k8s/pkg/provider/branch/cooldown"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
Expand All @@ -35,18 +30,35 @@ import (
fakeClient "sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

mock_condition "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/condition"
mock_k8s "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/k8s"
mock_node "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/node"
mock_manager "github.com/aws/amazon-vpc-resource-controller-k8s/mocks/amazon-vcp-resource-controller-k8s/pkg/node/manager"
"github.com/aws/amazon-vpc-resource-controller-k8s/pkg/config"
cooldown "github.com/aws/amazon-vpc-resource-controller-k8s/pkg/provider/branch/cooldown"
)

var (
mockConfigMap = &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{Name: config.VpcCniConfigMapName, Namespace: config.KubeSystemNamespace},
Data: map[string]string{config.EnableWindowsIPAMKey: "true", config.EnableWindowsPrefixDelegationKey: "true"},
Data: map[string]string{
config.EnableWindowsIPAMKey: "true",
config.EnableWindowsPrefixDelegationKey: "true",
config.WinMinimumIPTarget: strconv.Itoa(config.IPv4DefaultWinMinIPTarget),
config.WinWarmIPTarget: strconv.Itoa(config.IPv4DefaultWinWarmIPTarget),
},
}
mockConfigMapPD = &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{Name: config.VpcCniConfigMapName, Namespace: config.KubeSystemNamespace},
Data: map[string]string{config.EnableWindowsIPAMKey: "false", config.EnableWindowsPrefixDelegationKey: "true"},
Data: map[string]string{
config.EnableWindowsIPAMKey: "false",
config.EnableWindowsPrefixDelegationKey: "true",
config.WinMinimumIPTarget: strconv.Itoa(config.IPv4PDDefaultMinIPTargetSize),
config.WinWarmIPTarget: strconv.Itoa(config.IPv4PDDefaultWarmIPTargetSize),
},
}
mockConfigMapReq = reconcile.Request{
NamespacedName: types.NamespacedName{
Expand Down Expand Up @@ -89,11 +101,13 @@ func NewConfigMapMock(ctrl *gomock.Controller, mockObjects ...client.Object) Con
return ConfigMapMock{
MockNodeManager: mockNodeManager,
ConfigMapReconciler: &ConfigMapReconciler{
Client: client,
Log: zap.New(),
NodeManager: mockNodeManager,
K8sAPI: mockK8sWrapper,
Condition: mockCondition,
Client: client,
Log: zap.New(),
NodeManager: mockNodeManager,
K8sAPI: mockK8sWrapper,
Condition: mockCondition,
curWinMinIPTarget: config.IPv4DefaultWinMinIPTarget,
curWinWarmIPTarget: config.IPv4DefaultWinWarmIPTarget,
},
MockNode: mockNode,
MockK8sAPI: mockK8sWrapper,
Expand Down
5 changes: 3 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

crdv1alpha1 "github.com/aws/amazon-vpc-cni-k8s/pkg/apis/crd/v1alpha1"

vpcresourcesv1alpha1 "github.com/aws/amazon-vpc-resource-controller-k8s/apis/vpcresources/v1alpha1"
vpcresourcesv1beta1 "github.com/aws/amazon-vpc-resource-controller-k8s/apis/vpcresources/v1beta1"
"github.com/aws/amazon-vpc-resource-controller-k8s/controllers/apps"
Expand Down Expand Up @@ -143,8 +144,8 @@ func main() {
"Port for serving the introspection API")
flag.BoolVar(&enableWindowsPrefixDelegation, "enable-windows-prefix-delegation", false,
"Enable the feature flag for Windows prefix delegation")
flag.StringVar(&region, "aws-region", "", "The aws region of the k8s cluster")
flag.StringVar(&vpcID, "vpc-id", "", "The VPC ID where EKS cluster is deployed")
flag.StringVar(&region, "aws-region", "us-west-2", "The aws region of the k8s cluster")
flag.StringVar(&vpcID, "vpc-id", "vpc-09efbf2426cd7dc1a", "The VPC ID where EKS cluster is deployed")

flag.Parse()

Expand Down
99 changes: 71 additions & 28 deletions pkg/config/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ const (
// Default Configuration for Pod ENI resource type
PodENIDefaultWorker = 30

// Default Configuration for IPv4 resource type
IPv4DefaultWorker = 2
IPv4DefaultWPSize = 3
IPv4DefaultMaxDev = 1
IPv4DefaultResSize = 0

// Default Configuration for IPv4 prefix resource type
// Default Windows Configuration for IPv4 resource type
IPv4DefaultWinWorkerCount = 2
IPv4DefaultWinWarmIPTarget = 1
IPv4DefaultWinMinIPTarget = 3
IPv4DefaultWinMaxDev = 0
IPv4DefaultWinResSize = 0

// Default Windows Configuration for IPv4 prefix resource type
IPv4PDDefaultWorker = 2
IPv4PDDefaultWPSize = 1
IPv4PDDefaultMaxDev = 0
Expand Down Expand Up @@ -70,26 +71,43 @@ func LoadResourceConfig() map[string]ResourceConfig {
func LoadResourceConfigFromConfigMap(log logr.Logger, vpcCniConfigMap *v1.ConfigMap) map[string]ResourceConfig {
resourceConfig := getDefaultResourceConfig()

warmIPTarget, minIPTarget, warmPrefixTarget := ParseWinPDTargets(log, vpcCniConfigMap)
warmIPTarget, minIPTarget, warmPrefixTarget, isPDEnabled := ParseWinIPTargetConfigs(log, vpcCniConfigMap)

// If no PD configuration is set in configMap or none is valid, return default resource config
if warmIPTarget == 0 && minIPTarget == 0 && warmPrefixTarget == 0 {
return resourceConfig
}

resourceConfig[ResourceNameIPAddressFromPrefix].WarmPoolConfig.WarmIPTarget = warmIPTarget
resourceConfig[ResourceNameIPAddressFromPrefix].WarmPoolConfig.MinIPTarget = minIPTarget
resourceConfig[ResourceNameIPAddressFromPrefix].WarmPoolConfig.WarmPrefixTarget = warmPrefixTarget
if isPDEnabled {
resourceConfig[ResourceNameIPAddressFromPrefix].WarmPoolConfig.WarmIPTarget = warmIPTarget
resourceConfig[ResourceNameIPAddressFromPrefix].WarmPoolConfig.MinIPTarget = minIPTarget
resourceConfig[ResourceNameIPAddressFromPrefix].WarmPoolConfig.WarmPrefixTarget = warmPrefixTarget
} else {
resourceConfig[ResourceNameIPAddress].WarmPoolConfig.WarmIPTarget = warmIPTarget
resourceConfig[ResourceNameIPAddress].WarmPoolConfig.MinIPTarget = minIPTarget
resourceConfig[ResourceNameIPAddress].WarmPoolConfig.WarmPrefixTarget = warmPrefixTarget // ignore warm prefix in secondary IP mode
}

return resourceConfig
}

// ParseWinPDTargets parses config map for Windows prefix delegation configurations set by users
func ParseWinPDTargets(log logr.Logger, vpcCniConfigMap *v1.ConfigMap) (warmIPTarget int, minIPTarget int, warmPrefixTarget int) {
// ParseWinIPTargetConfigs parses Windows IP target configuration parameters in the amazon-vpc-cni ConfigMap
func ParseWinIPTargetConfigs(log logr.Logger, vpcCniConfigMap *v1.ConfigMap) (warmIPTarget int, minIPTarget int, warmPrefixTarget int, isPDEnabled bool) {
warmIPTarget, minIPTarget, warmPrefixTarget = 0, 0, 0

if vpcCniConfigMap.Data == nil {
return warmIPTarget, minIPTarget, warmPrefixTarget
log.V(1).Info("No configuration found in ConfigMap, falling back to using secondary IP mode with default values")
isPDEnabled = false
minIPTarget = IPv4DefaultWinMinIPTarget
warmIPTarget = IPv4DefaultWinWarmIPTarget
warmPrefixTarget = 0
return warmIPTarget, minIPTarget, warmPrefixTarget, isPDEnabled
}

isPDEnabled, err := strconv.ParseBool(vpcCniConfigMap.Data[EnableWindowsPrefixDelegationKey])
if err != nil {
log.V(1).Info("Failed to parse prefix delegation flag from ConfigMap, falling back to using secondary IP mode")
isPDEnabled = false
}

warmIPTargetStr, foundWarmIP := vpcCniConfigMap.Data[WarmIPTarget]
Expand All @@ -105,36 +123,59 @@ func ParseWinPDTargets(log logr.Logger, vpcCniConfigMap *v1.ConfigMap) (warmIPTa
warmPrefixTargetStr, foundWarmPrefix = vpcCniConfigMap.Data[WinWarmPrefixTarget]
}

// If no configuration is found, return 0
if !foundWarmIP && !foundMinIP && !foundWarmPrefix {
return warmIPTarget, minIPTarget, warmPrefixTarget
}

// Handle the scenario where warm IP target is not configured
if foundWarmIP {
warmIPTargetInt, err := strconv.Atoi(warmIPTargetStr)
if err != nil {
log.Error(err, "failed to parse warm ip target", "warm ip target", warmIPTargetStr)
log.Error(err, "failed to parse warm ip target, defaulting to zero", "warm ip target", warmIPTargetStr)
warmIPTarget = 0
} else {
warmIPTarget = warmIPTargetInt
}
} else {
log.V(1).Info("warm IP configuration not found in ConfigMap, will use default value")
if isPDEnabled {
warmIPTarget = IPv4PDDefaultWarmIPTargetSize
} else {
warmIPTarget = IPv4DefaultWinWarmIPTarget
}
}

// Handle the scenario where minimum IP target is not configured
if foundMinIP {
minIPTargetInt, err := strconv.Atoi(minIPTargetStr)
if err != nil {
log.Error(err, "failed to parse minimum ip target", "minimum ip target", minIPTargetStr)
log.Error(err, "failed to parse minimum ip target, defaulting to zero", "minimum ip target", minIPTargetStr)
minIPTarget = 0
} else {
minIPTarget = minIPTargetInt
}
} else {
log.V(1).Info("minimum IP configuration not found in ConfigMap, will use default value")
if isPDEnabled {
minIPTarget = IPv4PDDefaultMinIPTargetSize
} else {
minIPTarget = IPv4DefaultWinMinIPTarget
}
}
if foundWarmPrefix {

// Handle the scenario where warm prefix target is not configured
if !isPDEnabled && foundWarmPrefix {
log.V(1).Info("warm prefix configuration not supported in secondary IP mode, will ignore warm prefix configuration")
} else if isPDEnabled && foundWarmPrefix {
warmPrefixTargetInt, err := strconv.Atoi(warmPrefixTargetStr)
if err != nil {
log.Error(err, "failed to parse warm prefix target", "warm prefix target", warmPrefixTargetStr)
log.Error(err, "failed to parse warm prefix target, defaulting to zero", "warm prefix target", warmPrefixTargetStr)
warmPrefixTarget = 0
} else {
warmPrefixTarget = warmPrefixTargetInt
}
} else if isPDEnabled && !foundWarmPrefix {
log.V(1).Info("warm prefix configuration not found in ConfigMap, will use default value")
warmPrefixTarget = IPv4PDDefaultWarmPrefixTargetSize
}
return warmIPTarget, minIPTarget, warmPrefixTarget

return warmIPTarget, minIPTarget, warmPrefixTarget, isPDEnabled
}

// getDefaultResourceConfig returns the default Resource Configuration.
Expand All @@ -153,13 +194,15 @@ func getDefaultResourceConfig() map[string]ResourceConfig {

// Create default configuration for IPv4 Resource
ipV4WarmPoolConfig := WarmPoolConfig{
DesiredSize: IPv4DefaultWPSize,
MaxDeviation: IPv4DefaultMaxDev,
ReservedSize: IPv4DefaultResSize,
DesiredSize: IPv4DefaultWinWarmIPTarget,
WarmIPTarget: IPv4DefaultWinWarmIPTarget,
MinIPTarget: IPv4DefaultWinMinIPTarget,
MaxDeviation: IPv4DefaultWinMaxDev,
ReservedSize: IPv4DefaultWinResSize,
}
ipV4Config := ResourceConfig{
Name: ResourceNameIPAddress,
WorkerCount: IPv4DefaultWorker,
WorkerCount: IPv4DefaultWinWorkerCount,
SupportedOS: map[string]bool{OSWindows: true, OSLinux: false},
WarmPoolConfig: &ipV4WarmPoolConfig,
}
Expand Down
Loading

0 comments on commit ba0f44a

Please sign in to comment.