From 0845e4ecea5f420e832878ff0391db0de3863bdf Mon Sep 17 00:00:00 2001 From: jc2543 Date: Fri, 5 Jul 2024 13:41:50 -0700 Subject: [PATCH 1/3] Fix ACN PR Pipeline failures related to swiftv2 (#2826) fix stability of pr pipeline Co-authored-by: Chloe Chen --- .pipelines/multitenancy/swiftv2-e2e-step-template.yaml | 2 +- .pipelines/pipeline.yaml | 2 +- hack/aks/Makefile | 2 +- test/integration/manifests/swiftv2/podnetwork.yaml | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.pipelines/multitenancy/swiftv2-e2e-step-template.yaml b/.pipelines/multitenancy/swiftv2-e2e-step-template.yaml index 8ea1fa2741..6498144f4b 100644 --- a/.pipelines/multitenancy/swiftv2-e2e-step-template.yaml +++ b/.pipelines/multitenancy/swiftv2-e2e-step-template.yaml @@ -34,7 +34,7 @@ steps: kubectl get po -owide -A echo "Apply the pod network yaml to start the delegation" less test/integration/manifests/swiftv2/podnetwork.yaml - envsubst '${SUBNET_TOKEN},${SUBNET_GUID},${SUBNET_RESOURCE_ID},${VNET_GUID}' < test/integration/manifests/swiftv2/podnetwork.yaml | kubectl apply -f - + envsubst '${SUBNET_TOKEN},${SUBNET_RESOURCE_ID},${VNET_GUID}' < test/integration/manifests/swiftv2/podnetwork.yaml | kubectl apply -f - echo "Check the podnetwork yaml file" less test/integration/manifests/swiftv2/podnetwork.yaml kubectl get pn diff --git a/.pipelines/pipeline.yaml b/.pipelines/pipeline.yaml index e1ebacbc7f..538bbf593b 100644 --- a/.pipelines/pipeline.yaml +++ b/.pipelines/pipeline.yaml @@ -525,7 +525,7 @@ stages: clusterType: swiftv2-multitenancy-cluster-up clusterName: "mtacluster" nodePoolName: "mtapool" - vmSize: Standard_D4_v2 + vmSize: $(SWIFTV2_MT_CLUSTER_SKU) dependsOn: "test" dummyClusterName: "swiftv2dummy" dummyClusterType: "swiftv2-dummy-cluster-up" diff --git a/hack/aks/Makefile b/hack/aks/Makefile index 54b39d712f..d15a79b106 100644 --- a/hack/aks/Makefile +++ b/hack/aks/Makefile @@ -239,7 +239,7 @@ swiftv2-multitenancy-cluster-up: rg-up --network-plugin-mode overlay \ --kubernetes-version 1.28 \ --nodepool-name "mtapool" \ - --node-vm-size Standard_D4_v2 \ + --node-vm-size $(VM_SIZE) \ --node-count 2 \ --nodepool-tags fastpathenabled=true \ --no-ssh-key \ diff --git a/test/integration/manifests/swiftv2/podnetwork.yaml b/test/integration/manifests/swiftv2/podnetwork.yaml index ef289bb315..1998f2e5dc 100644 --- a/test/integration/manifests/swiftv2/podnetwork.yaml +++ b/test/integration/manifests/swiftv2/podnetwork.yaml @@ -5,6 +5,5 @@ metadata: kubernetes.azure.com/override-subnet-token: $SUBNET_TOKEN name: aksswiftvnetv20425 spec: - subnetGUID: $SUBNET_GUID subnetResourceID: $SUBNET_RESOURCE_ID vnetGUID: $VNET_GUID \ No newline at end of file From 438036f86d1f3638b00a990ae2dcda1945ebdda5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:42:08 -0700 Subject: [PATCH 2/3] deps: bump google.golang.org/grpc from 1.64.0 to 1.65.0 (#2829) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.65.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.65.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 9 ++++----- go.sum | 36 ++++++++---------------------------- 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 07fc749e72..05ebeebffe 100644 --- a/go.mod +++ b/go.mod @@ -38,8 +38,8 @@ require ( go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/sys v0.21.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/grpc v1.64.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 gopkg.in/natefinch/lumberjack.v2 v2.2.1 k8s.io/api v0.28.5 @@ -58,7 +58,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-iptables v0.7.0 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/docker v24.0.9+incompatible // indirect @@ -109,13 +109,12 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.24.0 golang.org/x/net v0.26.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.8 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index d1d96cf543..88c0ceaac9 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/billgraziano/dpapi v0.5.0 h1:pcxA17vyjbDqYuxCFZbgL9tYIk2xgbRZjRaIbATwh+8= github.com/billgraziano/dpapi v0.5.0/go.mod h1:lmEcZjRfLCSbUTsRu8V2ti6Q17MvnKn3N9gQqzDdTh0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0= @@ -127,8 +127,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -139,7 +137,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -295,7 +292,6 @@ github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZla github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -311,7 +307,6 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -324,7 +319,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -335,21 +329,18 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -365,10 +356,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -377,13 +365,10 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -398,7 +383,6 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -411,20 +395,18 @@ gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -434,8 +416,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 313ce0c4b07d30a86929878bd324264f90d94e7f Mon Sep 17 00:00:00 2001 From: shreyashastantram <105284415+shreyashastantram@users.noreply.github.com> Date: Fri, 5 Jul 2024 19:11:00 -0400 Subject: [PATCH 3/3] feat: Adding backend interfaces support to CNS (#2693) * Adding backend interfaces support for CNS * Fixing the log line * Moving backend nic functions to platform package * Moving the pnpID fetching to platform package * Moving the mapping to CRD mode * Moving macaddress parsing to net package function * removing the backend nic config * Handling multiple interface information * Adding error handling for macaddress parsing * Moving pnpid mapping to swift v2 flow * Adding pipeline vars * Adding ut's for Happy paths * Adding ut's for Happy paths * Adding mtpnc check * Rebasing with master * Addressing lint errors * Adding function to linux file * Addressing lint errors * Addressing lint comments * Addressing Lint issues * Modifying ut's * removing mutex lock on cache * Adding podnetwork instance label * Modifying ut's after change * Moving function out of restserver * Moving mapping after crd intial state * Adding the config debug statements * removing the unused config * Adding the debug statements * Adding the debug statements * Adding more debug logs * removing log lines and adding mtpnc status check * Moving mapping to state file * Rebasing and removing the debug statements * Addressing lint errors * removing the debug pipeline changes * Adding more coverage * Adding test coverage and unhappy paths * Addressing lint errors * addressing lint errors * Addressing lint errors --- cns/NetworkContainerContract.go | 16 +- cns/configuration/env.go | 9 +- cns/middlewares/k8sSwiftV2.go | 98 +++++++----- cns/middlewares/k8sSwiftV2_linux_test.go | 44 +++++- cns/middlewares/mock/mockClient.go | 86 ++++++++-- cns/restserver/ipam.go | 26 ++- cns/restserver/ipam_test.go | 193 +++++++++++++++++++++++ cns/restserver/restserver.go | 9 +- cns/restserver/util.go | 30 ++++ cns/restserver/util_test.go | 20 +++ cns/service/main.go | 10 +- cns/types/codes.go | 3 + crd/multitenancy/api/v1alpha1/utils.go | 27 +--- platform/mockexec.go | 8 + platform/osInterface.go | 2 + platform/os_linux.go | 8 + platform/os_windows.go | 67 ++++++++ platform/os_windows_test.go | 25 +++ 18 files changed, 589 insertions(+), 92 deletions(-) diff --git a/cns/NetworkContainerContract.go b/cns/NetworkContainerContract.go index b49fbfe456..3fa725b4a0 100644 --- a/cns/NetworkContainerContract.go +++ b/cns/NetworkContainerContract.go @@ -481,6 +481,8 @@ type PodIpInfo struct { SkipDefaultRoutes bool // Routes to configure on interface Routes []Route + // PnpId is set for backend interfaces, Pnp Id identifies VF. Plug and play id(pnp) is also called as PCI ID + PnPID string } type HostIPInfo struct { @@ -499,12 +501,14 @@ type IPConfigRequest struct { // Same as IPConfigRequest except that DesiredIPAddresses is passed in as a slice type IPConfigsRequest struct { - DesiredIPAddresses []string `json:"desiredIPAddresses"` - PodInterfaceID string `json:"podInterfaceID"` - InfraContainerID string `json:"infraContainerID"` - OrchestratorContext json.RawMessage `json:"orchestratorContext"` - Ifname string `json:"ifname"` // Used by delegated IPAM - SecondaryInterfacesExist bool `json:"secondaryInterfacesExist"` // will be set by SWIFT v2 validator func + DesiredIPAddresses []string `json:"desiredIPAddresses"` + PodInterfaceID string `json:"podInterfaceID"` + InfraContainerID string `json:"infraContainerID"` + OrchestratorContext json.RawMessage `json:"orchestratorContext"` + Ifname string `json:"ifname"` // Used by delegated IPAM + SecondaryInterfacesExist bool `json:"secondaryInterfacesExist"` // will be set by SWIFT v2 validator func + BackendInterfaceExist bool `json:"BackendInterfaceExist"` // will be set by SWIFT v2 validator func + BackendInterfaceMacAddresses []string `json:"BacknendInterfaceMacAddress"` } // IPConfigResponse is used in CNS IPAM mode as a response to CNI ADD diff --git a/cns/configuration/env.go b/cns/configuration/env.go index cf718a442b..1de6495ca0 100644 --- a/cns/configuration/env.go +++ b/cns/configuration/env.go @@ -14,10 +14,11 @@ const ( // LabelNodeSwiftV2 is the Node label for Swift V2 LabelNodeSwiftV2 = "kubernetes.azure.com/podnetwork-multi-tenancy-enabled" // LabelPodSwiftV2 is the Pod label for Swift V2 - LabelPodSwiftV2 = "kubernetes.azure.com/pod-network" - EnvPodCIDRs = "POD_CIDRs" - EnvServiceCIDRs = "SERVICE_CIDRs" - EnvInfraVNETCIDRs = "INFRA_VNET_CIDRs" + LabelPodSwiftV2 = "kubernetes.azure.com/pod-network" + LabelPodNetworkInstanceSwiftV2 = "kubernetes.azure.com/pod-network-instance" + EnvPodCIDRs = "POD_CIDRs" + EnvServiceCIDRs = "SERVICE_CIDRs" + EnvInfraVNETCIDRs = "INFRA_VNET_CIDRs" ) // ErrNodeNameUnset indicates the the $EnvNodeName variable is unset in the environment. diff --git a/cns/middlewares/k8sSwiftV2.go b/cns/middlewares/k8sSwiftV2.go index 1580ac8200..63d12fcb0c 100644 --- a/cns/middlewares/k8sSwiftV2.go +++ b/cns/middlewares/k8sSwiftV2.go @@ -82,15 +82,18 @@ func (k *K8sSWIFTv2Middleware) IPConfigsRequestHandlerWrapper(defaultHandler, fa // Set routes for the pod for i := range ipConfigsResp.PodIPInfo { ipInfo := &ipConfigsResp.PodIPInfo[i] - err = k.setRoutes(ipInfo) - if err != nil { - return &cns.IPConfigsResponse{ - Response: cns.Response{ - ReturnCode: types.FailedToAllocateIPConfig, - Message: fmt.Sprintf("AllocateIPConfig failed: %v, IP config request is %v", err, req), - }, - PodIPInfo: []cns.PodIpInfo{}, - }, errors.Wrapf(err, "failed to set routes for pod %s", podInfo.Name()) + // Backend nics doesn't need routes to be set + if ipInfo.NICType != cns.BackendNIC { + err = k.setRoutes(ipInfo) + if err != nil { + return &cns.IPConfigsResponse{ + Response: cns.Response{ + ReturnCode: types.FailedToAllocateIPConfig, + Message: fmt.Sprintf("AllocateIPConfig failed: %v, IP config request is %v", err, req), + }, + PodIPInfo: []cns.PodIpInfo{}, + }, errors.Wrapf(err, "failed to set routes for pod %s", podInfo.Name()) + } } } return ipConfigsResp, nil @@ -115,8 +118,10 @@ func (k *K8sSWIFTv2Middleware) validateIPConfigsRequest(ctx context.Context, req } // check the pod labels for Swift V2, set the request's SecondaryInterfaceSet flag to true and check if its MTPNC CRD is ready - if _, ok := pod.Labels[configuration.LabelPodSwiftV2]; ok { - req.SecondaryInterfacesExist = true + _, swiftV2PodNetworkLabel := pod.Labels[configuration.LabelPodSwiftV2] + _, swiftV2PodNetworkInstanceLabel := pod.Labels[configuration.LabelPodNetworkInstanceSwiftV2] + if swiftV2PodNetworkLabel || swiftV2PodNetworkInstanceLabel { + // Check if the MTPNC CRD exists for the pod, if not, return error mtpnc := v1alpha1.MultitenantPodNetworkConfig{} mtpncNamespacedName := k8stypes.NamespacedName{Namespace: podInfo.Namespace(), Name: podInfo.Name()} @@ -127,8 +132,27 @@ func (k *K8sSWIFTv2Middleware) validateIPConfigsRequest(ctx context.Context, req if !mtpnc.IsReady() { return nil, types.UnexpectedError, errMTPNCNotReady.Error() } + // If primary Ip is set in status field, it indicates the presence of secondary interfaces + if mtpnc.Status.PrimaryIP != "" { + req.SecondaryInterfacesExist = true + } + interfaceInfos := mtpnc.Status.InterfaceInfos + for _, interfaceInfo := range interfaceInfos { + if interfaceInfo.DeviceType == v1alpha1.DeviceTypeInfiniBandNIC { + if interfaceInfo.MacAddress == "" || interfaceInfo.NCID == "" { + return nil, types.UnexpectedError, errMTPNCNotReady.Error() + } + req.BackendInterfaceExist = true + req.BackendInterfaceMacAddresses = append(req.BackendInterfaceMacAddresses, interfaceInfo.MacAddress) + + } + if interfaceInfo.DeviceType == v1alpha1.DeviceTypeVnetNIC { + req.SecondaryInterfacesExist = true + } + } } logger.Printf("[SWIFTv2Middleware] pod %s has secondary interface : %v", podInfo.Name(), req.SecondaryInterfacesExist) + logger.Printf("[SWIFTv2Middleware] pod %s has backend interface : %v", podInfo.Name(), req.BackendInterfaceExist) // retrieve podinfo from orchestrator context return podInfo, types.Success, "" } @@ -171,19 +195,13 @@ func (k *K8sSWIFTv2Middleware) getIPConfig(ctx context.Context, podInfo cns.PodI // InterfaceName is empty for DelegatedVMNIC }) } else { - // Use InterfaceInfos if not empty - podIPInfos = make([]cns.PodIpInfo, len(mtpnc.Status.InterfaceInfos)) - for i, interfaceInfo := range mtpnc.Status.InterfaceInfos { - // Parse MTPNC primaryIP to get the IP address and prefix length - ip, prefixSize, err := utils.ParseIPAndPrefix(interfaceInfo.PrimaryIP) - if err != nil { - return nil, errors.Wrap(err, "failed to parse mtpnc primary IP and prefix") - } - if prefixSize != prefixLength { - return nil, errors.Wrapf(errInvalidMTPNCPrefixLength, "mtpnc primaryIP prefix length is %d", prefixSize) - } - - var nicType cns.NICType + for _, interfaceInfo := range mtpnc.Status.InterfaceInfos { + var ( + nicType cns.NICType + ip string + prefixSize int + err error + ) switch { case interfaceInfo.DeviceType == v1alpha1.DeviceTypeVnetNIC && !interfaceInfo.AccelnetEnabled: nicType = cns.DelegatedVMNIC @@ -194,19 +212,27 @@ func (k *K8sSWIFTv2Middleware) getIPConfig(ctx context.Context, podInfo cns.PodI default: nicType = cns.DelegatedVMNIC } - - podIPInfos[i] = cns.PodIpInfo{ - PodIPConfig: cns.IPSubnet{ - IPAddress: ip, - PrefixLength: uint8(prefixSize), - }, - MacAddress: interfaceInfo.MacAddress, - NICType: nicType, - SkipDefaultRoutes: false, - HostPrimaryIPInfo: cns.HostIPInfo{ - Gateway: interfaceInfo.GatewayIP, - }, + if nicType != cns.NodeNetworkInterfaceBackendNIC { + // Parse MTPNC primaryIP to get the IP address and prefix length + ip, prefixSize, err = utils.ParseIPAndPrefix(interfaceInfo.PrimaryIP) + if err != nil { + return nil, errors.Wrap(err, "failed to parse mtpnc primary IP and prefix") + } + if prefixSize != prefixLength { + return nil, errors.Wrapf(errInvalidMTPNCPrefixLength, "mtpnc primaryIP prefix length is %d", prefixSize) + } + podIPInfos = append(podIPInfos, cns.PodIpInfo{ + PodIPConfig: cns.IPSubnet{ + IPAddress: ip, + PrefixLength: uint8(prefixSize), + }, + MacAddress: interfaceInfo.MacAddress, + NICType: cns.DelegatedVMNIC, + SkipDefaultRoutes: false, + // InterfaceName is empty for DelegatedVMNIC + }) } + } } diff --git a/cns/middlewares/k8sSwiftV2_linux_test.go b/cns/middlewares/k8sSwiftV2_linux_test.go index 6042a08c19..d74324512d 100644 --- a/cns/middlewares/k8sSwiftV2_linux_test.go +++ b/cns/middlewares/k8sSwiftV2_linux_test.go @@ -31,6 +31,12 @@ var ( testPod7GUID = "123e4567-e89b-12d3-a456-426614174000" testPod7Info = cns.NewPodInfo("123e45-eth0", testPod7GUID, "testpod7", "testpod7namespace") + + testPod8GUID = "2006cad4-e54d-472e-863d-c4bac66200a7" + testPod8Info = cns.NewPodInfo("2006cad4-eth0", testPod8GUID, "testpod8", "testpod8namespace") + + testPod9GUID = "2006cad4-e54d-472e-863d-c4bac66200a7" + testPod9Info = cns.NewPodInfo("2006cad4-eth0", testPod9GUID, "testpod9", "testpod9namespace") ) func TestMain(m *testing.M) { @@ -141,6 +147,35 @@ func TestValidateMultitenantIPConfigsRequestSuccess(t *testing.T) { assert.Equal(t, err, "") assert.Equal(t, respCode, types.Success) assert.Equal(t, happyReq.SecondaryInterfacesExist, true) + + happyReq2 := &cns.IPConfigsRequest{ + PodInterfaceID: testPod8Info.InterfaceID(), + InfraContainerID: testPod8Info.InfraContainerID(), + } + + b, _ = testPod8Info.OrchestratorContext() + happyReq2.OrchestratorContext = b + happyReq2.SecondaryInterfacesExist = false + + _, respCode, err = middleware.validateIPConfigsRequest(context.TODO(), happyReq2) + assert.Equal(t, err, "") + assert.Equal(t, respCode, types.Success) + assert.Equal(t, happyReq.SecondaryInterfacesExist, true) + + happyReq3 := &cns.IPConfigsRequest{ + PodInterfaceID: testPod9Info.InterfaceID(), + InfraContainerID: testPod9Info.InfraContainerID(), + } + + b, _ = testPod9Info.OrchestratorContext() + happyReq3.OrchestratorContext = b + happyReq3.SecondaryInterfacesExist = false + + _, respCode, err = middleware.validateIPConfigsRequest(context.TODO(), happyReq3) + assert.Equal(t, err, "") + assert.Equal(t, respCode, types.Success) + assert.Equal(t, happyReq3.SecondaryInterfacesExist, false) + assert.Equal(t, happyReq3.BackendInterfaceExist, true) } func TestValidateMultitenantIPConfigsRequestFailure(t *testing.T) { @@ -373,11 +408,8 @@ func TestNICTypeConfigSuccess(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if len(ipInfos) != 1 { - t.Fatalf("expected 1 ipInfo, got %d", len(ipInfos)) - } - if ipInfos[0].NICType != cns.BackendNIC { - t.Errorf("expected NIC type %v, got %v", cns.BackendNIC, ipInfos[0].NICType) + if len(ipInfos) != 0 { + t.Fatalf("expected 0 ipInfo, got %d", len(ipInfos)) } } @@ -404,7 +436,7 @@ func TestGetSWIFTv2IPConfigMultiInterfaceSuccess(t *testing.T) { assert.Equal(t, err, nil) // Ensure that the length of ipInfos matches the number of InterfaceInfos // Adjust this according to the test setup in mock client - expectedInterfaceCount := 3 + expectedInterfaceCount := 2 assert.Equal(t, len(ipInfos), expectedInterfaceCount) for _, ipInfo := range ipInfos { diff --git a/cns/middlewares/mock/mockClient.go b/cns/middlewares/mock/mockClient.go index 4c2b1adfa9..229092c3dc 100644 --- a/cns/middlewares/mock/mockClient.go +++ b/cns/middlewares/mock/mockClient.go @@ -54,6 +54,18 @@ func NewClient() *Client { testPod7.Labels = make(map[string]string) testPod7.Labels[configuration.LabelPodSwiftV2] = podNetwork + testPod8 := v1.Pod{} + testPod8.Labels = make(map[string]string) + testPod8.Labels[configuration.LabelPodSwiftV2] = podNetwork + + testPod9 := v1.Pod{} + testPod9.Labels = make(map[string]string) + testPod9.Labels[configuration.LabelPodSwiftV2] = podNetwork + + testPod10 := v1.Pod{} + testPod10.Labels = make(map[string]string) + testPod10.Labels[configuration.LabelPodNetworkInstanceSwiftV2] = podNetwork + testInterfaceInfos1 := v1alpha1.InterfaceInfo{ NCID: "testncid", PrimaryIP: "192.168.0.1/32", @@ -107,22 +119,72 @@ func NewClient() *Client { }, } + testMTPNC8 := v1alpha1.MultitenantPodNetworkConfig{ + Status: v1alpha1.MultitenantPodNetworkConfigStatus{ + PrimaryIP: "192.168.0.1/32", + MacAddress: "00:00:00:00:00:00", + GatewayIP: "10.0.0.1", + NCID: "testncid", + InterfaceInfos: []v1alpha1.InterfaceInfo{ + { + PrimaryIP: "192.168.0.1/32", + MacAddress: "00:00:00:00:00:00", + GatewayIP: "10.0.0.1", + NCID: "testncid", + DeviceType: v1alpha1.DeviceTypeVnetNIC, + }, + { + PrimaryIP: "192.168.0.1/32", + MacAddress: "00:00:00:00:00:00", + GatewayIP: "10.0.0.1", + NCID: "testncid", + DeviceType: v1alpha1.DeviceTypeInfiniBandNIC, + }, + }, + }, + } + // Mtpnc with just Infiniband interface + testMTPNC9 := v1alpha1.MultitenantPodNetworkConfig{ + Status: v1alpha1.MultitenantPodNetworkConfigStatus{ + InterfaceInfos: []v1alpha1.InterfaceInfo{ + { + PrimaryIP: "192.168.0.1/32", + MacAddress: "00:00:00:00:00:00", + GatewayIP: "10.0.0.1", + NCID: "testncid", + DeviceType: v1alpha1.DeviceTypeInfiniBandNIC, + }, + }, + }, + } + + // Mtpnc with just Infiniband interface + testMTPNC10 := v1alpha1.MultitenantPodNetworkConfig{ + Status: v1alpha1.MultitenantPodNetworkConfigStatus{}, + } + return &Client{ mtPodCache: map[string]*v1.Pod{ - "testpod1namespace/testpod1": &testPod1, - "testpod3namespace/testpod3": &testPod3, - "testpod4namespace/testpod4": &testPod4, - "testpod5namespace/testpod5": &testPod5, - "testpod6namespace/testpod6": &testPod6, - "testpod7namespace/testpod7": &testPod7, + "testpod1namespace/testpod1": &testPod1, + "testpod3namespace/testpod3": &testPod3, + "testpod4namespace/testpod4": &testPod4, + "testpod5namespace/testpod5": &testPod5, + "testpod6namespace/testpod6": &testPod6, + "testpod7namespace/testpod7": &testPod7, + "testpod8namespace/testpod8": &testPod8, + "testpod9namespace/testpod9": &testPod9, + "testpod10namespace/testpod10": &testPod10, }, mtpncCache: map[string]*v1alpha1.MultitenantPodNetworkConfig{ - "testpod1namespace/testpod1": &testMTPNC1, - "testpod2namespace/testpod2": &testMTPNC2, - "testpod4namespace/testpod4": &testMTPNC4, - "testpod5namespace/testpod5": &testMTPNC3, - "testpod6namespace/testpod6": &testMTPNC5, - "testpod7namespace/testpod7": &testMTPNCMulti, + "testpod1namespace/testpod1": &testMTPNC1, + "testpod2namespace/testpod2": &testMTPNC2, + "testpod4namespace/testpod4": &testMTPNC4, + "testpod5namespace/testpod5": &testMTPNC3, + "testpod6namespace/testpod6": &testMTPNC5, + "testpod7namespace/testpod7": &testMTPNCMulti, + "testpod8namespace/testpod8": &testMTPNC8, + "testpod9namespace/testpod9": &testMTPNC9, + "testpod10namespace/testpod10": &testMTPNC10, }, } } diff --git a/cns/restserver/ipam.go b/cns/restserver/ipam.go index 689221ea69..b6116b0ef3 100644 --- a/cns/restserver/ipam.go +++ b/cns/restserver/ipam.go @@ -47,9 +47,30 @@ func (service *HTTPRestService) requestIPConfigHandlerHelper(ctx context.Context }, errors.New("failed to validate ip config request") } + var podIPInfoResult []cns.PodIpInfo + if ipconfigsRequest.BackendInterfaceExist { + for _, bNICMacAddress := range ipconfigsRequest.BackendInterfaceMacAddresses { + PnPID, err := service.getPNPIDFromMacAddress(ctx, bNICMacAddress) + if err != nil { + return &cns.IPConfigsResponse{ + Response: cns.Response{ + ReturnCode: types.FailedToAllocateIPConfig, + Message: fmt.Sprintf("BackendNIC allocation failed: %v, config request is %v", err, ipconfigsRequest), + }, + PodIPInfo: []cns.PodIpInfo{}, + }, err + } + podBackendInfo := cns.PodIpInfo{ + MacAddress: bNICMacAddress, + NICType: cns.BackendNIC, + PnPID: PnPID, + } + podIPInfoResult = append(podIPInfoResult, podBackendInfo) + } + } + // record a pod requesting an IP service.podsPendingIPAssignment.Push(podInfo.Key()) - podIPInfo, err := requestIPConfigsHelper(service, ipconfigsRequest) //nolint:contextcheck // appease linter for revert PR if err != nil { return &cns.IPConfigsResponse{ @@ -83,11 +104,12 @@ func (service *HTTPRestService) requestIPConfigHandlerHelper(ctx context.Context } } + podIPInfoResult = append(podIPInfoResult, podIPInfo...) return &cns.IPConfigsResponse{ Response: cns.Response{ ReturnCode: types.Success, }, - PodIPInfo: podIPInfo, + PodIPInfo: podIPInfoResult, }, nil } diff --git a/cns/restserver/ipam_test.go b/cns/restserver/ipam_test.go index a99c965bfe..9f4b582ada 100644 --- a/cns/restserver/ipam_test.go +++ b/cns/restserver/ipam_test.go @@ -52,6 +52,15 @@ var ( testIP4 = "10.0.0.4" testPod4GUID = "718e04ac-5a13-4dce-84b3-040accaa9b42" + testPod8GUID = "2006cad4-e54d-472e-863d-c4bac66200a7" + testPod8Info = cns.NewPodInfo("2006cad4-eth0", testPod8GUID, "testpod8", "testpod8namespace") + + testPod9GUID = "2006cad4-e54d-472e-863d-c4bac66200a9" + testPod9Info = cns.NewPodInfo("2006cad4-eth0", testPod9GUID, "testpod9", "testpod9namespace") + + testPod10GUID = "2006cad4-e54d-472e-863d-c4bac66200a9" + testPod10Info = cns.NewPodInfo("2006cad4-eth0", testPod10GUID, "testpod10", "testpod10namespace") + ipIDs = [][]string{{testIPID1, testIPID2, testIPID3}, {testIPID1v6, testIPID2v6, testIPID3v6}} ) @@ -156,6 +165,12 @@ func UpdatePodIPConfigState(t *testing.T, svc *HTTPRestService, ipconfigs map[st return nil } +func updatePnpIDMacAddressState(svc *HTTPRestService) { + svc.state.PnpIDByMacAddress = map[string]string{ + "00:00:00:00:00:00": "pnpid/pciid", + } +} + // create an endpoint with only one IP func TestEndpointStateReadAndWriteSingleNC(t *testing.T) { ncStates := []ncState{ @@ -1698,3 +1713,181 @@ func TestIPAMGetK8sSWIFTv2IPFailure(t *testing.T) { t.Fatal("Expected available ips to be 2 since we expect the IP to not be assigned") } } + +func TestIPAMGetK8sInfinibandSuccess(t *testing.T) { + svc := getTestService() + middleware := middlewares.K8sSWIFTv2Middleware{Cli: mock.NewClient()} + svc.AttachIPConfigsHandlerMiddleware(&middleware) + updatePnpIDMacAddressState(svc) + + t.Setenv(configuration.EnvPodCIDRs, "10.0.1.10/24") + t.Setenv(configuration.EnvServiceCIDRs, "10.0.2.10/24") + t.Setenv(configuration.EnvInfraVNETCIDRs, "10.0.3.10/24") + + ncStates := []ncState{ + { + ncID: testNCID, + ips: []string{ + testIP1, + }, + }, + { + ncID: testNCIDv6, + ips: []string{ + testIP1v6, + }, + }, + } + + // Add Available Pod IP to state + for i := range ncStates { + ipconfigs := make(map[string]cns.IPConfigurationStatus, 0) + state := NewPodState(ncStates[i].ips[0], ipIDs[i][0], ncStates[i].ncID, types.Available, 0) + ipconfigs[state.ID] = state + err := UpdatePodIPConfigState(t, svc, ipconfigs, ncStates[i].ncID) + if err != nil { + t.Fatalf("Expected to not fail adding IPs to state: %+v", err) + } + } + + req := cns.IPConfigsRequest{ + PodInterfaceID: testPod8Info.InterfaceID(), + InfraContainerID: testPod8Info.InfraContainerID(), + } + b, _ := testPod8Info.OrchestratorContext() + req.OrchestratorContext = b + req.DesiredIPAddresses = make([]string, 2) + req.DesiredIPAddresses[0] = testIP1 + req.DesiredIPAddresses[1] = testIP1v6 + + wrappedHandler := svc.IPConfigsHandlerMiddleware.IPConfigsRequestHandlerWrapper(svc.requestIPConfigHandlerHelper, svc.ReleaseIPConfigHandlerHelper) + resp, err := wrappedHandler(context.TODO(), req) + if err != nil { + t.Fatalf("Expected to not fail requesting IPs: %+v", err) + } + podIPInfo := resp.PodIPInfo + + if len(podIPInfo) != 4 { + t.Fatalf("Expected to get 4 pod IP info (IPv4, IPv6, Multitenant IP, Backend Nic), actual %d", len(podIPInfo)) + } + + // Asserting that SWIFT v2 IP is returned + assert.Equal(t, SWIFTv2IP, podIPInfo[3].PodIPConfig.IPAddress) + assert.Equal(t, SWIFTv2MAC, podIPInfo[3].MacAddress) + assert.Equal(t, cns.DelegatedVMNIC, podIPInfo[3].NICType) + assert.False(t, podIPInfo[3].SkipDefaultRoutes) +} + +// Test intednd to check for on single backend nic without the delegaed nic +func TestIPAMGetK8sInfinibandSuccessOneNic(t *testing.T) { + svc := getTestService() + middleware := middlewares.K8sSWIFTv2Middleware{Cli: mock.NewClient()} + svc.AttachIPConfigsHandlerMiddleware(&middleware) + updatePnpIDMacAddressState(svc) + + t.Setenv(configuration.EnvPodCIDRs, "10.0.1.10/24") + t.Setenv(configuration.EnvServiceCIDRs, "10.0.2.10/24") + t.Setenv(configuration.EnvInfraVNETCIDRs, "10.0.3.10/24") + + ncStates := []ncState{ + { + ncID: testNCID, + ips: []string{ + testIP1, + }, + }, + { + ncID: testNCIDv6, + ips: []string{ + testIP1v6, + }, + }, + } + + // Add Available Pod IP to state + for i := range ncStates { + ipconfigs := make(map[string]cns.IPConfigurationStatus, 0) + state := NewPodState(ncStates[i].ips[0], ipIDs[i][0], ncStates[i].ncID, types.Available, 0) + ipconfigs[state.ID] = state + err := UpdatePodIPConfigState(t, svc, ipconfigs, ncStates[i].ncID) + if err != nil { + t.Fatalf("Expected to not fail adding IPs to state: %+v", err) + } + } + + req := cns.IPConfigsRequest{ + PodInterfaceID: testPod9Info.InterfaceID(), + InfraContainerID: testPod9Info.InfraContainerID(), + } + b, _ := testPod9Info.OrchestratorContext() + req.OrchestratorContext = b + req.DesiredIPAddresses = make([]string, 2) + req.DesiredIPAddresses[0] = testIP1 + req.DesiredIPAddresses[1] = testIP1v6 + + wrappedHandler := svc.IPConfigsHandlerMiddleware.IPConfigsRequestHandlerWrapper(svc.requestIPConfigHandlerHelper, svc.ReleaseIPConfigHandlerHelper) + resp, err := wrappedHandler(context.TODO(), req) + if err != nil { + t.Fatalf("Expected to not fail requesting IPs: %+v", err) + } + podIPInfo := resp.PodIPInfo + + if len(podIPInfo) != 3 { + t.Fatalf("Expected to get 3 pod IP info (IPv4, IPv6, Multitenant IP), actual %d", len(podIPInfo)) + } + + assert.Equal(t, cns.BackendNIC, podIPInfo[0].NICType) +} + +func TestIPAMGetK8sInfinibandFailure(t *testing.T) { + svc := getTestService() + middleware := middlewares.K8sSWIFTv2Middleware{Cli: mock.NewClient()} + svc.AttachIPConfigsHandlerMiddleware(&middleware) + updatePnpIDMacAddressState(svc) + + t.Setenv(configuration.EnvPodCIDRs, "10.0.1.10/24") + t.Setenv(configuration.EnvServiceCIDRs, "10.0.2.10/24") + t.Setenv(configuration.EnvInfraVNETCIDRs, "10.0.3.10/24") + + ncStates := []ncState{ + { + ncID: testNCID, + ips: []string{ + testIP1, + }, + }, + { + ncID: testNCIDv6, + ips: []string{ + testIP1v6, + }, + }, + } + + // Add Available Pod IP to state + for i := range ncStates { + ipconfigs := make(map[string]cns.IPConfigurationStatus, 0) + state := NewPodState(ncStates[i].ips[0], ipIDs[i][0], ncStates[i].ncID, types.Available, 0) + ipconfigs[state.ID] = state + err := UpdatePodIPConfigState(t, svc, ipconfigs, ncStates[i].ncID) + if err != nil { + t.Fatalf("Expected to not fail adding IPs to state: %+v", err) + } + } + + req := cns.IPConfigsRequest{ + PodInterfaceID: testPod10Info.InterfaceID(), + InfraContainerID: testPod10Info.InfraContainerID(), + } + b, _ := testPod10Info.OrchestratorContext() + req.OrchestratorContext = b + req.DesiredIPAddresses = make([]string, 2) + req.DesiredIPAddresses[0] = testIP1 + req.DesiredIPAddresses[1] = testIP1v6 + + wrappedHandler := svc.IPConfigsHandlerMiddleware.IPConfigsRequestHandlerWrapper(svc.requestIPConfigHandlerHelper, svc.ReleaseIPConfigHandlerHelper) + _, err := wrappedHandler(context.TODO(), req) + if err == nil { + t.Fatalf("Expected failing requesting IPs due to not able to set routes") + } +} diff --git a/cns/restserver/restserver.go b/cns/restserver/restserver.go index cc17ef8724..a0eb0ba690 100644 --- a/cns/restserver/restserver.go +++ b/cns/restserver/restserver.go @@ -72,6 +72,7 @@ type HTTPRestService struct { cniConflistGenerator CNIConflistGenerator generateCNIConflistOnce sync.Once IPConfigsHandlerMiddleware cns.IPConfigsHandlerMiddleware + PnpIDByMacAddress map[string]string } type CNIConflistGenerator interface { @@ -150,6 +151,7 @@ type httpRestServiceState struct { TimeStamp time.Time joinedNetworks map[string]struct{} primaryInterface *wireserver.InterfaceInfo + PnpIDByMacAddress map[string]string } type networkInfo struct { @@ -192,9 +194,10 @@ func NewHTTPRestService(config *common.ServiceConfig, wscli interfaceGetter, wsp config.Server.PrimaryInterfaceIP = primaryInterface.PrimaryIP serviceState := &httpRestServiceState{ - Networks: make(map[string]*networkInfo), - joinedNetworks: make(map[string]struct{}), - primaryInterface: primaryInterface, + Networks: make(map[string]*networkInfo), + joinedNetworks: make(map[string]struct{}), + primaryInterface: primaryInterface, + PnpIDByMacAddress: make(map[string]string), } podIPIDByPodInterfaceKey := make(map[string][]string) diff --git a/cns/restserver/util.go b/cns/restserver/util.go index 94a51048e8..e9a1e33056 100644 --- a/cns/restserver/util.go +++ b/cns/restserver/util.go @@ -40,6 +40,36 @@ func (service *HTTPRestService) setNetworkInfo(networkName string, networkInfo * service.state.Networks[networkName] = networkInfo } +func (service *HTTPRestService) SavePnpIDMacaddressMapping(ctx context.Context) error { + // If mapping is already set, skip setting it again. + if len(service.state.PnpIDByMacAddress) != 0 { + return nil + } + p := platform.NewExecClient(nil) + vfMacAddressMapping, err := platform.FetchMacAddressPnpIDMapping(ctx, p) + if err != nil { + return errors.Wrap(err, "failed to fetch MACAddressPnpIDMapping") + } + service.state.PnpIDByMacAddress = vfMacAddressMapping + if err = service.saveState(); err != nil { + logger.Errorf("Failed to save mapping to statefile: %v", err) + } + return nil +} + +func (service *HTTPRestService) getPNPIDFromMacAddress(ctx context.Context, macAddress string) (string, error) { + // If map is empty in state file, CNS needs to populate state file before it returns back the response + if len(service.state.PnpIDByMacAddress) == 0 { + if err := service.SavePnpIDMacaddressMapping(ctx); err != nil { + return "", err + } + } + if _, ok := service.state.PnpIDByMacAddress[macAddress]; !ok { + return "", errors.New("Backend Network adapter not found") + } + return service.state.PnpIDByMacAddress[macAddress], nil +} + // Remove the network info from the service network state func (service *HTTPRestService) removeNetworkInfo(networkName string) { service.Lock() diff --git a/cns/restserver/util_test.go b/cns/restserver/util_test.go index 995c6e7486..56eede0e4e 100644 --- a/cns/restserver/util_test.go +++ b/cns/restserver/util_test.go @@ -1,9 +1,11 @@ package restserver import ( + "context" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestAreNCsPresent(t *testing.T) { @@ -159,3 +161,21 @@ func TestDeleteNCs(t *testing.T) { }) } } + +func TestGetPnpIDMapping(t *testing.T) { + svc := getTestService() + svc.state.PnpIDByMacAddress = map[string]string{ + "macaddress1": "value1", + } + pnpID, _ := svc.getPNPIDFromMacAddress(context.Background(), "macaddress1") + require.NotEmpty(t, pnpID) + + // Backend network adapter not found + _, err := svc.getPNPIDFromMacAddress(context.Background(), "macaddress8") + require.Error(t, err) + + // Empty pnpidmacaddress mapping + svc.state.PnpIDByMacAddress = map[string]string{} + _, err = svc.getPNPIDFromMacAddress(context.Background(), "macaddress8") + require.Error(t, err) +} diff --git a/cns/service/main.go b/cns/service/main.go index adcab93171..8391790060 100644 --- a/cns/service/main.go +++ b/cns/service/main.go @@ -805,7 +805,6 @@ func main() { logger.Errorf("Failed to set remote ARP MAC address: %v", err) return } - // We are only setting the PriorityVLANTag in 'cns.Direct' mode, because it neatly maps today, to 'isUsingMultitenancy' // In the future, we would want to have a better CNS flag, to explicitly say, this CNS is using multitenancy if cnsconfig.ChannelMode == cns.Direct { @@ -820,6 +819,7 @@ func main() { // Initialze state in if CNS is running in CRD mode // State must be initialized before we start HTTPRestService if config.ChannelMode == cns.CRD { + // Check the CNI statefile mount, and if the file is empty // stub an empty JSON object if err := cnireconciler.WriteObjectToCNIStatefile(); err != nil { @@ -860,6 +860,14 @@ func main() { logger.Errorf("Failed to start CRD Controller, err:%v.\n", err) return } + + if cnsconfig.EnableSwiftV2 { + // No-op for linux, mapping is set for windows in aks swiftv2 scenario + logger.Printf("Fetching backend nics for the node") + if err = httpRemoteRestService.SavePnpIDMacaddressMapping(rootCtx); err != nil { + logger.Errorf("Failed to fetch PnpIDMacaddress mapping: %v", err) + } + } } // Initialize multi-tenant controller if the CNS is running in MultiTenantCRD mode. diff --git a/cns/types/codes.go b/cns/types/codes.go index 24b98ddbfa..f96680231e 100644 --- a/cns/types/codes.go +++ b/cns/types/codes.go @@ -43,6 +43,7 @@ const ( NmAgentInternalServerError ResponseCode = 41 StatusUnauthorized ResponseCode = 42 UnsupportedAPI ResponseCode = 43 + FailedToAllocateBackendConfig ResponseCode = 44 UnexpectedError ResponseCode = 99 ) @@ -123,6 +124,8 @@ func (c ResponseCode) String() string { return "NmAgentInternalServerError" case StatusUnauthorized: return "StatusUnauthorized" + case FailedToAllocateBackendConfig: + return "FailedToAllocateBackendConfig" default: return "UnknownError" } diff --git a/crd/multitenancy/api/v1alpha1/utils.go b/crd/multitenancy/api/v1alpha1/utils.go index 28e3a51163..49bedd9358 100644 --- a/crd/multitenancy/api/v1alpha1/utils.go +++ b/crd/multitenancy/api/v1alpha1/utils.go @@ -1,28 +1,11 @@ package v1alpha1 +import ( + "reflect" +) + // IsReady checks if all the required fields in the MTPNC status are populated func (m *MultitenantPodNetworkConfig) IsReady() bool { // Check if InterfaceInfos slice is not empty - if len(m.Status.InterfaceInfos) == 0 { - // Check if the higher fields in the status are populated - if m.Status.PrimaryIP == "" || - m.Status.MacAddress == "" || - m.Status.NCID == "" || - m.Status.GatewayIP == "" { - return false - } - } else { - // Check if each InterfaceInfo has all required fields populated - for _, interfaceInfo := range m.Status.InterfaceInfos { - if interfaceInfo.NCID == "" || - interfaceInfo.PrimaryIP == "" || - interfaceInfo.MacAddress == "" || - interfaceInfo.GatewayIP == "" || - interfaceInfo.DeviceType == "" { - return false - } - } - } - - return true + return !reflect.DeepEqual(m.Status, MultitenantPodNetworkConfigStatus{}) } diff --git a/platform/mockexec.go b/platform/mockexec.go index d8b4a60bae..c0471983da 100644 --- a/platform/mockexec.go +++ b/platform/mockexec.go @@ -1,6 +1,7 @@ package platform import ( + "context" "errors" "time" ) @@ -63,3 +64,10 @@ func (e *MockExecClient) GetLastRebootTime() (time.Time, error) { func (e *MockExecClient) KillProcessByName(_ string) error { return nil } + +func (e *MockExecClient) ExecutePowershellCommandWithContext(_ context.Context, cmd string) (string, error) { + if e.powershellCommandResponder != nil { + return e.powershellCommandResponder(cmd) + } + return "", nil +} diff --git a/platform/osInterface.go b/platform/osInterface.go index fa3a91ed8d..a70f6203d3 100644 --- a/platform/osInterface.go +++ b/platform/osInterface.go @@ -1,6 +1,7 @@ package platform import ( + "context" "time" "go.uber.org/zap" @@ -21,6 +22,7 @@ type ExecClient interface { GetLastRebootTime() (time.Time, error) ClearNetworkConfiguration() (bool, error) ExecutePowershellCommand(command string) (string, error) + ExecutePowershellCommandWithContext(ctx context.Context, command string) (string, error) KillProcessByName(processName string) error } diff --git a/platform/os_linux.go b/platform/os_linux.go index 0b29bb2868..e6c2197284 100644 --- a/platform/os_linux.go +++ b/platform/os_linux.go @@ -136,6 +136,10 @@ func (p *execClient) ExecutePowershellCommand(_ string) (string, error) { return "", nil } +func (p *execClient) ExecutePowershellCommandWithContext(_ context.Context, _ string) (string, error) { + return "", nil +} + func (p *execClient) KillProcessByName(processName string) error { cmd := fmt.Sprintf("pkill -f %v", processName) _, err := p.ExecuteCommand(cmd) @@ -200,3 +204,7 @@ func HasMellanoxAdapter() bool { // Not needed for Linux func MonitorAndSetMellanoxRegKeyPriorityVLANTag(_ context.Context, _ int) {} + +func FetchMacAddressPnpIDMapping(_ context.Context, _ ExecClient) (map[string]string, error) { + return nil, nil +} diff --git a/platform/os_windows.go b/platform/os_windows.go index e4de7b8dcd..064d479698 100644 --- a/platform/os_windows.go +++ b/platform/os_windows.go @@ -7,6 +7,7 @@ import ( "bytes" "context" "fmt" + "net" "os" "os/exec" "strings" @@ -72,6 +73,9 @@ const ( CheckIfHNSStatePathExistsCommand = "Test-Path " + "-Path HKLM:\\SYSTEM\\CurrentControlSet\\Services\\hns\\State" + // Command to fetch netadapter and pnp id + GetMacAddressVFPPnpIDMapping = "Get-NetAdapter | Select-Object MacAddress, PnpDeviceID| Format-Table -HideTableHeaders" + // Command to restart HNS service RestartHnsServiceCommand = "Restart-Service -Name hns" @@ -82,6 +86,8 @@ const ( // reg key value for PriorityVLANTag = 3 --> Packet priority and VLAN enabled // for more details goto https://learn.microsoft.com/en-us/windows-hardware/drivers/network/standardized-inf-keywords-for-ndis-qos desiredVLANTagForMellanox = 3 + // Powershell command timeout + ExecTimeout = 10 * time.Second ) // Flag to check if sdnRemoteArpMacAddress registry key is set @@ -194,6 +200,34 @@ func (p *execClient) ExecutePowershellCommand(command string) (string, error) { return strings.TrimSpace(stdout.String()), nil } +// ExecutePowershellCommandWithContext executes powershell command wth context +func (p *execClient) ExecutePowershellCommandWithContext(ctx context.Context, command string) (string, error) { + ps, err := exec.LookPath("powershell.exe") + if err != nil { + return "", errors.New("failed to find powershell executable") + } + + if p.logger != nil { + p.logger.Info("[Azure-Utils]", zap.String("command", command)) + } else { + log.Printf("[Azure-Utils] %s", command) + } + + cmd := exec.CommandContext(ctx, ps, command) + var stdout bytes.Buffer + var stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + err = cmd.Run() + if err != nil { + ErrPowershellExecution := errors.New("failed to execute powershell command") + return "", fmt.Errorf("%w:%s", ErrPowershellExecution, stderr.String()) + } + + return strings.TrimSpace(stdout.String()), nil +} + // SetSdnRemoteArpMacAddress sets the regkey for SDNRemoteArpMacAddress needed for multitenancy if hns is enabled func SetSdnRemoteArpMacAddress(execClient ExecClient) error { exists, err := execClient.ExecutePowershellCommand(CheckIfHNSStatePathExistsCommand) @@ -343,3 +377,36 @@ func ReplaceFile(source, destination string) error { return windows.MoveFileEx(src, dest, windows.MOVEFILE_REPLACE_EXISTING|windows.MOVEFILE_WRITE_THROUGH) } + +/* +Output: +6C-A1-00-50-E4-2D PCI\VEN_8086&DEV_2723&SUBSYS_00808086&REV_1A\4&328243d9&0&00E0 +80-6D-97-1E-CF-4E USB\VID_17EF&PID_A359\3010019E3 +*/ +func FetchMacAddressPnpIDMapping(ctx context.Context, execClient ExecClient) (map[string]string, error) { + ctx, cancel := context.WithTimeout(ctx, ExecTimeout) + defer cancel() // The cancel should be deferred so resources are cleaned up + output, err := execClient.ExecutePowershellCommandWithContext(ctx, GetMacAddressVFPPnpIDMapping) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch VF mapping") + } + result := make(map[string]string) + if output != "" { + // Split the output based on new line characters + lines := strings.Split(output, "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + // Split based on " " to fetch the macaddress and pci id + parts := strings.Split(line, " ") + // Changing the format of macaddress from xx-xx-xx-xx to xx:xx:xx:xx + formattedMacaddress, err := net.ParseMAC(parts[0]) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch MACAddressPnpIDMapping") + } + key := formattedMacaddress.String() + value := parts[1] + result[key] = value + } + } + return result, nil +} diff --git a/platform/os_windows_test.go b/platform/os_windows_test.go index 424c30227f..7c86441781 100644 --- a/platform/os_windows_test.go +++ b/platform/os_windows_test.go @@ -1,6 +1,7 @@ package platform import ( + "context" "errors" "os/exec" "strings" @@ -134,3 +135,27 @@ func TestSetSdnRemoteArpMacAddress_hnsEnabled(t *testing.T) { // reset sdnRemoteArpMacAddressSet sdnRemoteArpMacAddressSet = false } + +func TestFetchPnpIDMapping(t *testing.T) { + mockExecClient := NewMockExecClient(false) + // happy path + mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) { + return "6C-A1-00-50-E4-2D PCI\\VEN_8086&DEV_2723&SUBSYS_00808086&REV_1A\\4&328243d9&0&00E0\n80-6D-97-1E-CF-4E USB\\VID_17EF&PID_A359\\3010019E3", nil + }) + vfmapping, _ := FetchMacAddressPnpIDMapping(context.Background(), mockExecClient) + require.Len(t, 2, len(vfmapping)) + + // Test when no adapters are found + mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) { + return "", nil + }) + vfmapping, _ = FetchMacAddressPnpIDMapping(context.Background(), mockExecClient) + require.Empty(t, 0, len(vfmapping)) + // Adding carriage returns + mockExecClient.SetPowershellCommandResponder(func(cmd string) (string, error) { + return "6C-A1-00-50-E4-2D PCI\\VEN_8086&DEV_2723&SUBSYS_00808086&REV_1A\\4&328243d9&0&00E0\r\n\r80-6D-97-1E-CF-4E USB\\VID_17EF&PID_A359\\3010019E3", nil + }) + + vfmapping, _ = FetchMacAddressPnpIDMapping(context.Background(), mockExecClient) + require.Len(t, 2, len(vfmapping)) +}