Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 31 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Terway Project Development Guide

## Dev environment tips

- Use `make help` to see all available make targets and their descriptions
- Run `make generate` to generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations
- Use `make manifests` to generate CustomResourceDefinition objects
- Run `make fmt` to format Go code with `go fmt`
- Use `make vet` to run `go vet` against code with build tags

## Testing instructions

- Find the CI plan in the `.github/workflows` folder (check.yml, build.yml)
- Run `make quick-test` to run all tests
- Run `make lint` to run golangci-lint with the configuration in `.golangci.yml`
- Run `make lint-fix` to run golangci-lint and perform automatic fixes
- Fix any test or lint errors until the whole suite passes
- After moving files or changing imports, run `make fmt` and `make vet` to ensure code quality
- Add or update tests for the code you change, even if nobody asked

## PR instructions

- Title format: `[terway] <Title>` or `[component] <Title>`
- Always run `make lint` and `make test` before committing
- Ensure `go mod tidy` and `go mod vendor` are run before submitting (checked in CI)
- Make sure all build tags are properly set (privileged, default_build)
- Verify that your changes pass the GitHub Actions workflows:
- Code formatting and linting (golangci-lint)
- Unit tests with coverage
- Module vendoring checks
- Super-linter for markdown and bash files
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ vet: ## Run go vet against code.
test: manifests generate fmt vet envtest datapath-test## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test -gcflags=all=-l -race --tags "$(GO_BUILD_TAGS)" $$(go list ./... | grep -Ev '/e2e|/mocks|/generated|/apis|/examples|/tests|/rpc|/windows|/internal/testutil') -coverprofile coverage.txt

.PHONY: test-quick
test-quick: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test -gcflags=all=-l -race --tags "$(GO_BUILD_TAGS)" $$(go list ./... | grep -Ev '/e2e|/mocks|/generated|/apis|/examples|/tests|/rpc|/windows|/internal/testutil') -coverprofile coverage.txt

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter & yamllint
$(GOLANGCI_LINT) run
Expand Down
24 changes: 12 additions & 12 deletions cmd/terway-cli/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"testing"

"github.com/agiledragon/gomonkey/v2"
"github.com/stretchr/testify/assert"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"

"github.com/AliyunContainerService/terway/pkg/aliyun/metadata"
)
Expand Down Expand Up @@ -42,12 +42,12 @@ func TestPrintKV(t *testing.T) {
func TestArgumentValidation(t *testing.T) {
t.Run("runList argument validation", func(t *testing.T) {
cmd := &cobra.Command{}

// Test with exactly 2 arguments (should fail)
err := runList(cmd, []string{"arg1", "arg2"})
assert.Error(t, err)
assert.Contains(t, err.Error(), "too many arguments")

// Test with more than 2 arguments (should fail)
err = runList(cmd, []string{"arg1", "arg2", "arg3"})
assert.Error(t, err)
Expand All @@ -56,17 +56,17 @@ func TestArgumentValidation(t *testing.T) {

t.Run("runShow argument validation", func(t *testing.T) {
cmd := &cobra.Command{}

// Test with no arguments
err := runShow(cmd, []string{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "no arguments")

// Test with 2 or more arguments
err = runShow(cmd, []string{"type", "name"})
assert.Error(t, err)
assert.Contains(t, err.Error(), "too many arguments")

// Test with 3 arguments
err = runShow(cmd, []string{"type", "name", "extra"})
assert.Error(t, err)
Expand All @@ -75,28 +75,28 @@ func TestArgumentValidation(t *testing.T) {

t.Run("runExecute argument validation", func(t *testing.T) {
cmd := &cobra.Command{}

// Test with no arguments
err := runExecute(cmd, []string{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "too few arguments")

// Test with 1 argument
err = runExecute(cmd, []string{"type"})
assert.Error(t, err)
assert.Contains(t, err.Error(), "too few arguments")

// Test with 2 arguments
err = runExecute(cmd, []string{"type", "name"})
assert.Error(t, err)
assert.Contains(t, err.Error(), "too few arguments")

// Test with exactly 3 arguments should pass validation
// We don't call runExecute here since it will access nil client
// Instead, we verify the argument parsing logic
args := []string{"type", "name", "command"}
assert.True(t, len(args) >= 3, "Should have at least 3 arguments")

// Verify argument assignment logic
typ, name, command := args[0], args[1], args[2]
remainingArgs := args[3:]
Expand Down Expand Up @@ -556,4 +556,4 @@ func TestRunMetadata_ErrorCases(t *testing.T) {
err := runMetadata(cmd, []string{})
assert.NoError(t, err)
})
}
}
2 changes: 1 addition & 1 deletion daemon/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ func (b *NetworkServiceBuilder) PostInitForCRDV2() *NetworkServiceBuilder {
if b.err != nil {
return b
}
crdv2 := eni.NewCRDV2(b.service.k8s.NodeName(), b.namespace)
crdv2 := eni.NewCRDV2(b.service.k8s.GetRestConfig(), b.service.k8s.NodeName(), b.namespace)
mgr := eni.NewManager(nil, 0, []eni.NetworkInterface{crdv2}, daemon.EniSelectionPolicy(b.config.EniSelectionPolicy), nil)

svc := b.RunENIMgr(b.ctx, mgr)
Expand Down
61 changes: 23 additions & 38 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ var serviceLog = logf.Log.WithName("server")
var _ rpc.TerwayBackendServer = (*networkService)(nil)

// return resource relation in db, or return nil.
func (n *networkService) getPodResource(info *daemon.PodInfo) (daemon.PodResources, error) {
obj, err := n.resourceDB.Get(utils.PodInfoKey(info.Namespace, info.Name))
func (n *networkService) getPodResource(podID string) (daemon.PodResources, error) {
obj, err := n.resourceDB.Get(podID)
if err == nil {
return obj.(daemon.PodResources), nil
}
Expand All @@ -98,9 +98,8 @@ func (n *networkService) getPodResource(info *daemon.PodInfo) (daemon.PodResourc
return daemon.PodResources{}, err
}

func (n *networkService) deletePodResource(info *daemon.PodInfo) error {
key := utils.PodInfoKey(info.Namespace, info.Name)
return n.resourceDB.Delete(key)
func (n *networkService) deletePodResource(podID string) error {
return n.resourceDB.Delete(podID)
}

func (n *networkService) AllocIP(ctx context.Context, r *rpc.AllocIPRequest) (*rpc.AllocIPReply, error) {
Expand Down Expand Up @@ -163,7 +162,7 @@ func (n *networkService) AllocIP(ctx context.Context, r *rpc.AllocIPRequest) (*r
}

// 2. Find old resource info
oldRes, err := n.getPodResource(pod)
oldRes, err := n.getPodResource(podID)
if err != nil {
return nil, &types.Error{
Code: types.ErrInternalError,
Expand Down Expand Up @@ -331,30 +330,31 @@ func (n *networkService) ReleaseIP(ctx context.Context, r *rpc.ReleaseIPRequest)
// 0. Get pod Info
pod, err := n.k8s.GetPod(ctx, r.K8SPodNamespace, r.K8SPodName, true)
if err != nil {
if k8sErr.IsNotFound(err) {
return reply, nil
if !k8sErr.IsNotFound(err) {
l.Error(err, "get pod failed")
// ignore error, do not block delete
}
return nil, err
}

cni := &daemon.CNI{
PodName: r.K8SPodName,
PodNamespace: r.K8SPodNamespace,
PodID: podID,
PodUID: pod.PodUID,
}

var podIpStickTime time.Duration
if pod != nil {
cni.PodUID = pod.PodUID
podIpStickTime = pod.IPStickTime
}

// 1. Init Context

oldRes, err := n.getPodResource(pod)
oldRes, err := n.getPodResource(podID)
if err != nil {
return nil, err
}

if !n.verifyPodNetworkType(pod.PodNetworkType) {
return nil, fmt.Errorf("unexpect pod network type allocate, maybe daemon mode changed: %+v", pod.PodNetworkType)
}

if oldRes.ContainerID != nil {
if r.K8SPodInfraContainerId != *oldRes.ContainerID {
l.Info("cni request not match stored resource, ignored", "old", *oldRes.ContainerID)
Expand All @@ -365,7 +365,7 @@ func (n *networkService) ReleaseIP(ctx context.Context, r *rpc.ReleaseIPRequest)
cni.PodUID = oldRes.PodInfo.PodUID
}

if n.ipamType == types.IPAMTypeCRD || pod.IPStickTime == 0 {
if n.ipamType == types.IPAMTypeCRD || podIpStickTime <= 0 {
for _, resource := range oldRes.Resources {
res := parseNetworkResource(resource)
if res == nil {
Expand All @@ -379,7 +379,7 @@ func (n *networkService) ReleaseIP(ctx context.Context, r *rpc.ReleaseIPRequest)
return nil, err
}
}
err = n.deletePodResource(pod)
err = n.deletePodResource(podID)
if err != nil {
return nil, fmt.Errorf("error delete pod resource: %w", err)
}
Expand All @@ -388,6 +388,7 @@ func (n *networkService) ReleaseIP(ctx context.Context, r *rpc.ReleaseIPRequest)
return reply, nil
}

// GetIPInfo return cached alloc ip info
func (n *networkService) GetIPInfo(ctx context.Context, r *rpc.GetInfoRequest) (*rpc.GetInfoReply, error) {
podID := utils.PodInfoKey(r.K8SPodNamespace, r.K8SPodName)
log := logf.FromContext(ctx)
Expand All @@ -409,27 +410,17 @@ func (n *networkService) GetIPInfo(ctx context.Context, r *rpc.GetInfoRequest) (

var err error

// 0. Get pod Info
pod, err := n.k8s.GetPod(ctx, r.K8SPodNamespace, r.K8SPodName, true)
if err != nil {
return nil, &types.Error{
Code: types.ErrInvalidArgsErrCode,
Msg: err.Error(),
R: err,
}
}

// 1. Init Context
reply := &rpc.GetInfoReply{
Success: true,
IPv4: n.enableIPv4,
IPv6: n.enableIPv6,
}

switch pod.PodNetworkType {
case daemon.PodNetworkTypeENIMultiIP:
switch n.daemonMode {
case daemon.ModeENIMultiIP:
reply.IPType = rpc.IPType_TypeENIMultiIP
case daemon.PodNetworkTypeVPCENI:
case daemon.ModeENIOnly:
reply.IPType = rpc.IPType_TypeVPCENI
default:
return nil, &types.Error{
Expand All @@ -439,7 +430,7 @@ func (n *networkService) GetIPInfo(ctx context.Context, r *rpc.GetInfoRequest) (
}

// 2. Find old resource info
oldRes, err := n.getPodResource(pod)
oldRes, err := n.getPodResource(podID)
if err != nil {
return nil, &types.Error{
Code: types.ErrInternalError,
Expand All @@ -448,12 +439,6 @@ func (n *networkService) GetIPInfo(ctx context.Context, r *rpc.GetInfoRequest) (
}
}

if !n.verifyPodNetworkType(pod.PodNetworkType) {
return nil, &types.Error{
Code: types.ErrInvalidArgsErrCode,
Msg: "Unexpected network type, maybe daemon mode changed",
}
}
if oldRes.ContainerID != nil {
if r.K8SPodInfraContainerId != *oldRes.ContainerID {
log.Info("cni request not match stored resource, ignored", "old", *oldRes.ContainerID)
Expand Down Expand Up @@ -640,7 +625,7 @@ func (n *networkService) gcPods(ctx context.Context) error {
}
}

err = n.deletePodResource(podRes.PodInfo)
err = n.deletePodResource(podID)
if err != nil {
return err
}
Expand Down
Loading
Loading