Skip to content

Commit

Permalink
Refactor(instance): Refactor the way instance metadata is retrieved
Browse files Browse the repository at this point in the history
- Modify the logic for retrieving instance metadata, optimizing with interfaces and caching
- Refactor the way EFLO instance metadata is retrieved
- Update relevant unit tests

Signed-off-by: l1b0k <[email protected]>
  • Loading branch information
l1b0k committed Feb 19, 2025
1 parent 2f8cb10 commit 7f48420
Show file tree
Hide file tree
Showing 38 changed files with 1,274 additions and 427 deletions.
56 changes: 53 additions & 3 deletions cmd/terway-cli/cni_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package main
import (
"errors"
"fmt"
"strconv"
"strings"
"syscall"

"github.com/docker/docker/pkg/parsers/kernel"
"github.com/vishvananda/netlink"
utilfeature "k8s.io/apiserver/pkg/util/feature"

Expand Down Expand Up @@ -60,6 +62,54 @@ func allowEBPFNetworkPolicy(require bool) (bool, error) {
return require, nil
}

func checkKernelVersion(k, major, minor int) bool {
return kernel.CheckKernelVersion(k, major, minor)
func checkKernelVersion(iMajor, iMinor, iPatch int) bool {
var un syscall.Utsname
syscall.Uname(&un)
var sb strings.Builder
for _, b := range un.Release[:] {
if b == 0 {
break

Check warning on line 71 in cmd/terway-cli/cni_linux.go

View check run for this annotation

Codecov / codecov/patch

cmd/terway-cli/cni_linux.go#L65-L71

Added lines #L65 - L71 were not covered by tests
}
sb.WriteByte(byte(b))

Check warning on line 73 in cmd/terway-cli/cni_linux.go

View check run for this annotation

Codecov / codecov/patch

cmd/terway-cli/cni_linux.go#L73

Added line #L73 was not covered by tests
}
major, minor, patch, ok := parseRelease(sb.String())
return ok && (major > iMajor ||
major == iMajor && minor > iMinor ||
major == iMajor && minor == iMinor && iPatch >= patch)

Check warning on line 78 in cmd/terway-cli/cni_linux.go

View check run for this annotation

Codecov / codecov/patch

cmd/terway-cli/cni_linux.go#L75-L78

Added lines #L75 - L78 were not covered by tests
}

// parseRelease parses a dot-separated version number. It follows the semver
// syntax, but allows the minor and patch versions to be elided.
//
// This is a copy of the Go runtime's parseRelease from
// https://golang.org/cl/209597.
func parseRelease(rel string) (major, minor, patch int, ok bool) {
// Strip anything after a dash or plus.
for i := 0; i < len(rel); i++ {
if rel[i] == '-' || rel[i] == '+' {
rel = rel[:i]
break

Check warning on line 91 in cmd/terway-cli/cni_linux.go

View check run for this annotation

Codecov / codecov/patch

cmd/terway-cli/cni_linux.go#L86-L91

Added lines #L86 - L91 were not covered by tests
}
}

next := func() (int, bool) {
for i := 0; i < len(rel); i++ {
if rel[i] == '.' {
ver, err := strconv.Atoi(rel[:i])
rel = rel[i+1:]
return ver, err == nil
}

Check warning on line 101 in cmd/terway-cli/cni_linux.go

View check run for this annotation

Codecov / codecov/patch

cmd/terway-cli/cni_linux.go#L95-L101

Added lines #L95 - L101 were not covered by tests
}
ver, err := strconv.Atoi(rel)
rel = ""
return ver, err == nil

Check warning on line 105 in cmd/terway-cli/cni_linux.go

View check run for this annotation

Codecov / codecov/patch

cmd/terway-cli/cni_linux.go#L103-L105

Added lines #L103 - L105 were not covered by tests
}
if major, ok = next(); !ok || rel == "" {
return
}
if minor, ok = next(); !ok || rel == "" {
return
}
patch, ok = next()
return

Check warning on line 114 in cmd/terway-cli/cni_linux.go

View check run for this annotation

Codecov / codecov/patch

cmd/terway-cli/cni_linux.go#L107-L114

Added lines #L107 - L114 were not covered by tests
}
74 changes: 62 additions & 12 deletions daemon/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ type NetworkServiceBuilder struct {

limit *client.Limits

err error
eflo bool
err error
}

func NewNetworkServiceBuilder(ctx context.Context) *NetworkServiceBuilder {
Expand Down Expand Up @@ -120,6 +121,10 @@ func (b *NetworkServiceBuilder) InitK8S() *NetworkServiceBuilder {
b.service.daemonMode = daemon.ModeENIOnly
}

if utils.ISLinJunNode(b.service.k8s.Node().Labels) {
b.eflo = true
instance.Init(&instance.EFLO{})
}

Check warning on line 127 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L124-L127

Added lines #L124 - L127 were not covered by tests
return b
}

Expand Down Expand Up @@ -152,10 +157,10 @@ func (b *NetworkServiceBuilder) LoadDynamicConfig() *NetworkServiceBuilder {
}

func (b *NetworkServiceBuilder) setupAliyunClient() error {
if os.Getenv("TERWAY_DEPLOY_ENV") == envEFLO {
instance.SetPopulateFunc(instance.EfloPopulate)
regionID, err := instance.GetInstanceMeta().GetRegionID()
if err != nil {
return err

Check warning on line 162 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L160-L162

Added lines #L160 - L162 were not covered by tests
}
meta := instance.GetInstanceMeta()

var providers []credential.Interface
if string(b.config.AccessID) != "" && string(b.config.AccessSecret) != "" {
Expand All @@ -164,7 +169,7 @@ func (b *NetworkServiceBuilder) setupAliyunClient() error {
providers = append(providers, credential.NewEncryptedCredentialProvider(utils.NormalizePath(b.config.CredentialPath)))
providers = append(providers, credential.NewMetadataProvider())

clientSet, err := credential.NewClientMgr(meta.RegionID, providers...)
clientSet, err := credential.NewClientMgr(regionID, providers...)

Check warning on line 172 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L172

Added line #L172 was not covered by tests
if err != nil {
return err
}
Expand All @@ -184,14 +189,18 @@ func (b *NetworkServiceBuilder) initInstanceLimit() error {
return fmt.Errorf("k8s node not found")
}
provider := client.LimitProviders["ecs"]
if os.Getenv("TERWAY_DEPLOY_ENV") == envEFLO {
if b.eflo {

Check warning on line 192 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L192

Added line #L192 was not covered by tests
provider = client.LimitProviders["eflo"]
limit, err := provider.GetLimitFromAnno(node.Annotations)
if err != nil {
return err
}
if limit == nil {
limit, err = provider.GetLimit(b.aliyunClient, instance.GetInstanceMeta().InstanceID)
instanceID, err := instance.GetInstanceMeta().GetInstanceID()
if err != nil {
return err
}
limit, err = provider.GetLimit(b.aliyunClient, instanceID)

Check warning on line 203 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L199-L203

Added lines #L199 - L203 were not covered by tests
if err != nil {
return fmt.Errorf("upable get instance limit, %w", err)
}
Expand All @@ -202,10 +211,28 @@ func (b *NetworkServiceBuilder) initInstanceLimit() error {
if err != nil {
return err
}
if limit == nil || instance.GetInstanceMeta().InstanceType != limit.InstanceTypeID {
limit, err = provider.GetLimit(b.aliyunClient, instance.GetInstanceMeta().InstanceType)

if limit != nil {
instanceType, err := instance.GetInstanceMeta().GetInstanceType()

Check warning on line 216 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L215-L216

Added lines #L215 - L216 were not covered by tests
if err != nil {
return fmt.Errorf("upable get instance limit, %w", err)
return err
}
if limit.InstanceTypeID != instanceType {
limit = nil
}

Check warning on line 222 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L218-L222

Added lines #L218 - L222 were not covered by tests
}

if limit == nil {
instanceType, err := instance.GetInstanceMeta().GetInstanceType()
if err != nil {
return err
}

Check warning on line 229 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L225-L229

Added lines #L225 - L229 were not covered by tests

if instanceType != limit.InstanceTypeID {
limit, err = provider.GetLimit(b.aliyunClient, instanceType)
if err != nil {
return fmt.Errorf("upable get instance limit, %w", err)
}

Check warning on line 235 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L231-L235

Added lines #L231 - L235 were not covered by tests
}
}
b.limit = limit
Expand All @@ -227,6 +254,29 @@ func (b *NetworkServiceBuilder) setupENIManager() error {
eniConfig.EnableIPv4 = enableIPv4
eniConfig.EnableIPv6 = enableIPv6

zoneID, err := instance.GetInstanceMeta().GetZoneID()
if err != nil {
return err
}
instanceID, err := instance.GetInstanceMeta().GetInstanceID()
if err != nil {
return err
}
vswitchID, err := instance.GetInstanceMeta().GetVSwitchID()
if err != nil {
return err
}

Check warning on line 268 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L257-L268

Added lines #L257 - L268 were not covered by tests

if eniConfig.ZoneID == "" {
eniConfig.ZoneID = zoneID
}
if eniConfig.InstanceID == "" {
eniConfig.InstanceID = instanceID
}
if len(eniConfig.VSwitchOptions) == 0 {
eniConfig.VSwitchOptions = []string{vswitchID}
}

Check warning on line 278 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L270-L278

Added lines #L270 - L278 were not covered by tests

// fall back to use primary eni's sg
if len(eniConfig.SecurityGroupIDs) == 0 {
enis, err := b.aliyunClient.DescribeNetworkInterface(b.ctx, "", nil, eniConfig.InstanceID, "Primary", "", nil)
Expand Down Expand Up @@ -361,7 +411,7 @@ func (b *NetworkServiceBuilder) setupENIManager() error {
eniList = append(eniList, eni.NewLocal(nil, "secondary", factory, poolConfig))
}

eniManager := eni.NewManager(poolConfig.MinPoolSize, poolConfig.MaxPoolSize, poolConfig.Capacity, 30*time.Second, eniList, types.EniSelectionPolicy(b.config.EniSelectionPolicy), b.service.k8s)
eniManager := eni.NewManager(poolConfig.MinPoolSize, poolConfig.MaxPoolSize, poolConfig.Capacity, 30*time.Second, eniList, daemon.EniSelectionPolicy(b.config.EniSelectionPolicy), b.service.k8s)

Check warning on line 414 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L414

Added line #L414 was not covered by tests
b.service.eniMgr = eniManager
err = eniManager.Run(b.ctx, &b.service.wg, podResources)
if err != nil {
Expand Down Expand Up @@ -405,7 +455,7 @@ func (b *NetworkServiceBuilder) PostInitForCRDV2() *NetworkServiceBuilder {
return b
}
crdv2 := eni.NewCRDV2(b.service.k8s.NodeName(), b.namespace)
mgr := eni.NewManager(0, 0, 0, 0, []eni.NetworkInterface{crdv2}, types.EniSelectionPolicy(b.config.EniSelectionPolicy), nil)
mgr := eni.NewManager(0, 0, 0, 0, []eni.NetworkInterface{crdv2}, daemon.EniSelectionPolicy(b.config.EniSelectionPolicy), nil)

Check warning on line 458 in daemon/builder.go

View check run for this annotation

Codecov / codecov/patch

daemon/builder.go#L458

Added line #L458 was not covered by tests

svc := b.RunENIMgr(b.ctx, mgr)
go b.service.startGarbageCollectionLoop(b.ctx)
Expand Down
23 changes: 8 additions & 15 deletions daemon/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"

"github.com/AliyunContainerService/terway/pkg/aliyun/client"
"github.com/AliyunContainerService/terway/pkg/aliyun/instance"
"github.com/AliyunContainerService/terway/pkg/k8s"
"github.com/AliyunContainerService/terway/pkg/utils"
"github.com/AliyunContainerService/terway/pkg/vswitch"
Expand All @@ -25,26 +24,24 @@ func getDynamicConfig(ctx context.Context, k8s k8s.Kubernetes) (string, string,
return cfg, label, err
}

func getENIConfig(cfg *daemon.Config) *types.ENIConfig {
func getENIConfig(cfg *daemon.Config) *daemon.ENIConfig {
vswitchSelectionPolicy := vswitch.VSwitchSelectionPolicyRandom
switch cfg.VSwitchSelectionPolicy {
case "ordered":
// keep the previous behave
vswitchSelectionPolicy = vswitch.VSwitchSelectionPolicyMost
}

eniSelectionPolicy := types.EniSelectionPolicyMostIPs
eniSelectionPolicy := daemon.EniSelectionPolicyMostIPs
switch cfg.EniSelectionPolicy {
case "least_ips":
eniSelectionPolicy = types.EniSelectionPolicyLeastIPs
eniSelectionPolicy = daemon.EniSelectionPolicyLeastIPs

Check warning on line 38 in daemon/config.go

View check run for this annotation

Codecov / codecov/patch

daemon/config.go#L38

Added line #L38 was not covered by tests
}

eniConfig := &types.ENIConfig{
ZoneID: instance.GetInstanceMeta().ZoneID,
eniConfig := &daemon.ENIConfig{
VSwitchOptions: nil,
ENITags: cfg.ENITags,
SecurityGroupIDs: cfg.GetSecurityGroups(),
InstanceID: instance.GetInstanceMeta().InstanceID,
VSwitchSelectionPolicy: vswitchSelectionPolicy,
EniSelectionPolicy: eniSelectionPolicy,
ResourceGroupID: cfg.ResourceGroupID,
Expand All @@ -59,24 +56,20 @@ func getENIConfig(cfg *daemon.Config) *types.ENIConfig {
}
}

if len(eniConfig.VSwitchOptions) == 0 {
eniConfig.VSwitchOptions = []string{instance.GetInstanceMeta().VSwitchID}
}

if cfg.EnableENITrunking {
types.EnableFeature(&eniConfig.EniTypeAttr, types.FeatTrunk)
daemon.EnableFeature(&eniConfig.EniTypeAttr, daemon.FeatTrunk)
}
if cfg.EnableERDMA {
types.EnableFeature(&eniConfig.EniTypeAttr, types.FeatERDMA)
daemon.EnableFeature(&eniConfig.EniTypeAttr, daemon.FeatERDMA)
}

return eniConfig
}

// the actual size for pool is minIdle and maxIdle
func getPoolConfig(cfg *daemon.Config, daemonMode string, limit *client.Limits) (*types.PoolConfig, error) {
func getPoolConfig(cfg *daemon.Config, daemonMode string, limit *client.Limits) (*daemon.PoolConfig, error) {

poolConfig := &types.PoolConfig{
poolConfig := &daemon.PoolConfig{
BatchSize: 10,
}

Expand Down
67 changes: 49 additions & 18 deletions daemon/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,51 @@ import (
"github.com/AliyunContainerService/terway/pkg/aliyun/client"
"github.com/AliyunContainerService/terway/pkg/aliyun/instance"
"github.com/AliyunContainerService/terway/pkg/vswitch"
"github.com/AliyunContainerService/terway/types"
"github.com/AliyunContainerService/terway/types/daemon"
)

func init() {
instance.SetPopulateFunc(func() *instance.Instance {
return &instance.Instance{
RegionID: "regionID",
ZoneID: "zoneID",
VPCID: "vpc",
VSwitchID: "vsw",
PrimaryMAC: "",
InstanceID: "instanceID",
InstanceType: "",
}
})
type Mock struct {
regionID string
zoneID string
vSwitchID string
primaryMAC string
instanceID string
instanceType string
}

func (m *Mock) GetRegionID() (string, error) {
return m.regionID, nil
}

func (m *Mock) GetZoneID() (string, error) {
return m.zoneID, nil
}

func (m *Mock) GetVSwitchID() (string, error) {
return m.vSwitchID, nil
}

func (m *Mock) GetPrimaryMAC() (string, error) {
return m.primaryMAC, nil
}

func (m *Mock) GetInstanceID() (string, error) {
return m.instanceID, nil
}

func (m *Mock) GetInstanceType() (string, error) {
return m.instanceType, nil
}

func TestGetPoolConfigWithENIMultiIPMode(t *testing.T) {
instance.Init(&Mock{
regionID: "regionID",
zoneID: "zoneID",
vSwitchID: "vsw",
primaryMAC: "",
instanceID: "instanceID",
instanceType: "",
})
cfg := &daemon.Config{
MaxPoolSize: 5,
MinPoolSize: 1,
Expand All @@ -46,6 +72,14 @@ func TestGetPoolConfigWithENIMultiIPMode(t *testing.T) {
}

func TestGetENIConfig(t *testing.T) {
instance.Init(&Mock{
regionID: "regionID",
zoneID: "zoneID",
vSwitchID: "vsw",
primaryMAC: "",
instanceID: "instanceID",
instanceType: "",
})
cfg := &daemon.Config{
ENITags: map[string]string{"aa": "bb"},
SecurityGroups: []string{"sg1", "sg2"},
Expand All @@ -61,13 +95,10 @@ func TestGetENIConfig(t *testing.T) {

eniConfig := getENIConfig(cfg)

assert.Equal(t, "zoneID", eniConfig.ZoneID)
assert.Equal(t, []string{"vswitch1", "vswitch2"}, eniConfig.VSwitchOptions)
assert.Equal(t, 1, len(eniConfig.ENITags))
assert.Equal(t, []string{"sg1", "sg2"}, eniConfig.SecurityGroupIDs)
assert.Equal(t, "instanceID", eniConfig.InstanceID)
assert.Equal(t, vswitch.VSwitchSelectionPolicyMost, eniConfig.VSwitchSelectionPolicy)
assert.Equal(t, types.EniSelectionPolicyMostIPs, eniConfig.EniSelectionPolicy)
assert.Equal(t, daemon.EniSelectionPolicyMostIPs, eniConfig.EniSelectionPolicy)
assert.Equal(t, "rgID", eniConfig.ResourceGroupID)
assert.Equal(t, types.Feat(3), eniConfig.EniTypeAttr)
assert.Equal(t, daemon.Feat(3), eniConfig.EniTypeAttr)
}
4 changes: 2 additions & 2 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ func checkInstance(limit *client.Limits, daemonMode string, config *daemon.Confi
}

// initTrunk to ensure trunk eni is present. Return eni id if found.
func initTrunk(config *daemon.Config, poolConfig *types.PoolConfig, k8sClient k8s.Kubernetes, f factory.Factory) (string, error) {
func initTrunk(config *daemon.Config, poolConfig *daemon.PoolConfig, k8sClient k8s.Kubernetes, f factory.Factory) (string, error) {
var err error

// get eni id form node annotation
Expand Down Expand Up @@ -909,7 +909,7 @@ func initTrunk(config *daemon.Config, poolConfig *types.PoolConfig, k8sClient k8
return trunk.ID, nil
}

func runDevicePlugin(daemonMode string, config *daemon.Config, poolConfig *types.PoolConfig) {
func runDevicePlugin(daemonMode string, config *daemon.Config, poolConfig *daemon.PoolConfig) {

Check warning on line 912 in daemon/daemon.go

View check run for this annotation

Codecov / codecov/patch

daemon/daemon.go#L912

Added line #L912 was not covered by tests
switch daemonMode {
case daemon.ModeENIMultiIP:
if config.EnableENITrunking {
Expand Down
Loading

0 comments on commit 7f48420

Please sign in to comment.