Repository: kubernetes-sigs/cloud-provider-azure
Pull request #2946 (2022-12-15 02:01:11)

[release 1.24] build: run golangci-lint in Github Action and enable errorlint
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide/first-contribution.md#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issuepr-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

#### What type of PR is this?
/kind cleanup 
<!--
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->

#### What this PR does / why we need it:
cherry-pick #2868 and #2923 

#### Which issue(s) this PR fixes:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->
```release-note
NONE
```

#### Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:

<!--
This section can be blank if this pull request does not require a release note.

When adding links which point to resources within git repositories, like
KEPs or supporting documentation, please reference a specific commit and avoid
linking directly to the master branch. This ensures that links reference a
specific point in time, rather than a document that may change over time.

See here for guidance on getting permanent links to files: https://help.github.com/en/articles/getting-permanent-links-to-files

Please use the following format for linking documentation:
- [KEP]: <link>
- [Usage]: <link>
- [Other doc]: <link>
-->
```docs

```



Patch:
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
new file mode 100644
index 000000000..d68b3da4f
--- /dev/null
+++ b/.github/workflows/lint.yaml
@@ -0,0 +1,20 @@
+name: Code Lint
+
+on:
+  workflow_dispatch:
+  push:
+  pull_request:
+
+jobs:
+  Lint:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Setup Golang
+        uses: actions/setup-go@v3
+        with:
+          go-version-file: go.mod
+      - name: Lint
+        run: |
+          make lint
diff --git a/.golangci.yml b/.golangci.yml
index e10f54519..34bd705e1 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,26 +1,45 @@
 run:
-  deadline: 30m
-  concurrency: 2
+  timeout: 30m
   go: '1.18'
-  allow-serial-runners: true
-skip-dirs:
+  tests: true
+  skip-dirs:
     - vendor
 linters:
   disable-all: true
   enable:
-    - LINTER_TO_RUN
-  # Run with --fast=false for more extensive checks
+    - errcheck
+    - goconst
+    - gofmt
+    - goimports
+    - revive
+    - gosec
+    - gosimple
+    - govet
+    - ineffassign
+    - misspell
+    - nakedret
+    - staticcheck
+    - typecheck
+    - unconvert
+    - unused
+    - asasalint
+    - asciicheck
+    - bidichk
+    - errorlint
+    - loggercheck
   fast: false
-  govet:
-    # Report about shadowed variables.
-    # Default: false
-    check-shadowing: true
 issues:
   exclude-rules:
     - path: tests/e2e
       linters:
         - revive
-  #include:
-  #  - EXC0002 # include "missing comments" issues from golint
   max-issues-per-linter: 0
   max-same-issues: 0
+linters-settings:
+  staticcheck:
+    checks: ["all", "-SA1019"]
+  gosec:
+    excludes:
+      - G114
+  goimports:
+    local-prefixes: sigs.k8s.io/cloud-provider-azure
diff --git a/Makefile b/Makefile
index 4f01dbc7e..09e9ebd48 100644
--- a/Makefile
+++ b/Makefile
@@ -316,11 +316,11 @@ ifdef JUNIT
 endif
 
 .PHONY: test-check
-test-check: test-lint test-boilerplate test-helm verify-vendor-licenses ## Run all static checks.
+test-check: test-boilerplate test-helm verify-vendor-licenses ## Run all static checks.
 
-.PHONY: test-lint
-test-lint: ## Run golint test.
-	hack/verify-golint.sh
+.PHONY: lint
+lint: golangci-lint ## Run golangci-lint against code.
+	$(LINTER) run -v
 
 .PHONY: test-boilerplate
 test-boilerplate: ## Run boilerplate test.
@@ -399,3 +399,12 @@ endif
 .PHONY: deploy-cluster
 deploy-cluster:
 	hack/deploy-cluster-capz.sh
+
+##@ Tools
+
+LINTER = $(shell pwd)/bin/golangci-lint
+LINTER_VERSION = v1.50.1
+.PHONY: golangci-lint
+golangci-lint:  ## Download golangci-lint locally if necessary.
+	@echo "Installing golangci-lint"
+	@test -s $(LINTER) || curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/$(LINTER_VERSION)/install.sh | sh -s -- -b $(shell pwd)/bin $(LINTER_VERSION)
diff --git a/cmd/acr-credential-provider/main.go b/cmd/acr-credential-provider/main.go
index f19d141d5..12297be2f 100644
--- a/cmd/acr-credential-provider/main.go
+++ b/cmd/acr-credential-provider/main.go
@@ -27,6 +27,7 @@ import (
 	"github.com/spf13/cobra"
 	"k8s.io/component-base/logs"
 	"k8s.io/klog/v2"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/credentialprovider"
 )
 
diff --git a/cmd/acr-credential-provider/plugin.go b/cmd/acr-credential-provider/plugin.go
index 9005eac48..1a9a34bb0 100644
--- a/cmd/acr-credential-provider/plugin.go
+++ b/cmd/acr-credential-provider/plugin.go
@@ -30,6 +30,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime/serializer/json"
 	"k8s.io/kubelet/pkg/apis/credentialprovider/install"
 	"k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/credentialprovider"
 )
 
@@ -140,7 +141,7 @@ func encodeResponse(response *v1alpha1.CredentialProviderResponse) ([]byte, erro
 	encoder := codecs.EncoderForVersion(info.Serializer, v1alpha1.SchemeGroupVersion)
 	data, err := runtime.Encode(encoder, response)
 	if err != nil {
-		return nil, fmt.Errorf("failed to encode response: %v", err)
+		return nil, fmt.Errorf("failed to encode response: %w", err)
 	}
 
 	return data, nil
diff --git a/cmd/cloud-controller-manager/controller-manager.go b/cmd/cloud-controller-manager/controller-manager.go
index 6500b2eed..78af7b036 100644
--- a/cmd/cloud-controller-manager/controller-manager.go
+++ b/cmd/cloud-controller-manager/controller-manager.go
@@ -25,10 +25,9 @@ import (
 	"time"
 
 	"k8s.io/component-base/logs"
-	"sigs.k8s.io/cloud-provider-azure/cmd/cloud-controller-manager/app"
-
 	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugins
 
+	"sigs.k8s.io/cloud-provider-azure/cmd/cloud-controller-manager/app"
 	_ "sigs.k8s.io/cloud-provider-azure/pkg/provider"
 )
 
diff --git a/cmd/cloud-node-manager/node-manager.go b/cmd/cloud-node-manager/node-manager.go
index c132a8470..74c8c69e8 100644
--- a/cmd/cloud-node-manager/node-manager.go
+++ b/cmd/cloud-node-manager/node-manager.go
@@ -25,10 +25,9 @@ import (
 	"time"
 
 	"k8s.io/component-base/logs"
-	"sigs.k8s.io/cloud-provider-azure/cmd/cloud-node-manager/app"
-
 	_ "k8s.io/component-base/metrics/prometheus/clientgo" // load all the prometheus client-go plugins
 
+	"sigs.k8s.io/cloud-provider-azure/cmd/cloud-node-manager/app"
 	_ "sigs.k8s.io/cloud-provider-azure/pkg/provider"
 )
 
diff --git a/hack/verify-golint.sh b/hack/verify-golint.sh
deleted file mode 100755
index 1cf2c3a6e..000000000
--- a/hack/verify-golint.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-
-# Copyright 2020 The Kubernetes Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -euo pipefail
-
-if [[ -z "$(command -v golangci-lint)" ]]; then
-  echo "Cannot find golangci-lint. Installing golangci-lint..."
-  go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.0
-  export PATH=$PATH:$(go env GOPATH)/bin
-fi
-
-echo "Verifying golint"
-readonly PKG_ROOT="$(git rev-parse --show-toplevel)"
-
-LINTERS=("deadcode" "errcheck" "goconst" "gofmt" "goimports" "revive" "gosec" "gosimple" "govet" "ineffassign" "misspell" "nakedret" "staticcheck" "structcheck" "typecheck" "unconvert" "unused" "varcheck" )
-GOLANGCI_YML="${PKG_ROOT}/.golangci.yml"
-GOLANGCI_YML_TEST="${PKG_ROOT}/.golangci-test.yml"
-for LINTER in "${LINTERS[@]}"; do
-  cp -rf "${GOLANGCI_YML}" "${GOLANGCI_YML_TEST}"
-  sed -i "s|LINTER_TO_RUN|${LINTER}|g" "${GOLANGCI_YML_TEST}"
-  golangci-lint run -v --config "${GOLANGCI_YML_TEST}"
-  echo ""
-done
-
-echo "Congratulations! Lint check completed for all Go source files."
diff --git a/pkg/azureclients/armclient/azure_armclient.go b/pkg/azureclients/armclient/azure_armclient.go
index e113f3636..864911ad7 100644
--- a/pkg/azureclients/armclient/azure_armclient.go
+++ b/pkg/azureclients/armclient/azure_armclient.go
@@ -30,13 +30,12 @@ import (
 	"time"
 	"unicode"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
-
 	"github.com/Azure/go-autorest/autorest"
 	"github.com/Azure/go-autorest/autorest/azure"
 	"github.com/Azure/go-autorest/tracing"
-
 	"k8s.io/klog/v2"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 	"sigs.k8s.io/cloud-provider-azure/pkg/version"
 )
diff --git a/pkg/azureclients/armclient/util.go b/pkg/azureclients/armclient/util.go
index 0505043d9..f66e40c73 100644
--- a/pkg/azureclients/armclient/util.go
+++ b/pkg/azureclients/armclient/util.go
@@ -30,6 +30,7 @@ import (
 	"github.com/Azure/go-autorest/autorest"
 	"k8s.io/client-go/util/flowcontrol"
 	"k8s.io/klog/v2"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
diff --git a/pkg/azureclients/containerserviceclient/interface.go b/pkg/azureclients/containerserviceclient/interface.go
index 98ff18d8a..477b6b4fb 100644
--- a/pkg/azureclients/containerserviceclient/interface.go
+++ b/pkg/azureclients/containerserviceclient/interface.go
@@ -20,6 +20,7 @@ import (
 	"context"
 
 	"github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2021-10-01/containerservice"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
 
diff --git a/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient.go b/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient.go
index cb513c18e..8d2ab07de 100644
--- a/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient.go
+++ b/pkg/azureclients/virtualnetworklinksclient/azure_virtualnetworklinksclient.go
@@ -27,6 +27,7 @@ import (
 	"github.com/Azure/go-autorest/autorest/azure"
 	"k8s.io/client-go/util/flowcontrol"
 	"k8s.io/klog/v2"
+
 	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/metrics"
diff --git a/pkg/azureclients/virtualnetworklinksclient/interface.go b/pkg/azureclients/virtualnetworklinksclient/interface.go
index ff8c6c2df..5087bf601 100644
--- a/pkg/azureclients/virtualnetworklinksclient/interface.go
+++ b/pkg/azureclients/virtualnetworklinksclient/interface.go
@@ -20,6 +20,7 @@ import (
 	"context"
 
 	"github.com/Azure/azure-sdk-for-go/services/privatedns/mgmt/2018-09-01/privatedns"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
 
diff --git a/pkg/azureclients/vmasclient/interface.go b/pkg/azureclients/vmasclient/interface.go
index 07ecb9ac1..4e303f16b 100644
--- a/pkg/azureclients/vmasclient/interface.go
+++ b/pkg/azureclients/vmasclient/interface.go
@@ -20,6 +20,7 @@ import (
 	"context"
 
 	"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-03-01/compute"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
 
diff --git a/pkg/azureclients/vmsizeclient/interface.go b/pkg/azureclients/vmsizeclient/interface.go
index 119d55e9e..8c595d0f3 100644
--- a/pkg/azureclients/vmsizeclient/interface.go
+++ b/pkg/azureclients/vmsizeclient/interface.go
@@ -20,6 +20,7 @@ import (
 	"context"
 
 	"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-03-01/compute"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
 )
 
diff --git a/pkg/credentialprovider/azure_acr_helper.go b/pkg/credentialprovider/azure_acr_helper.go
index a7482f748..4fdf3a70a 100644
--- a/pkg/credentialprovider/azure_acr_helper.go
+++ b/pkg/credentialprovider/azure_acr_helper.go
@@ -91,13 +91,13 @@ func receiveChallengeFromLoginServer(serverAddress, scheme string) (*authDirecti
 	var r *http.Request
 	r, err = http.NewRequest("GET", challengeURL.String(), nil)
 	if err != nil {
-		return nil, fmt.Errorf("failed to construct request, got %v", err)
+		return nil, fmt.Errorf("failed to construct request, got %w", err)
 	}
 	r.Header.Add(userAgentHeader, userAgent)
 
 	var challenge *http.Response
 	if challenge, err = client.Do(r); err != nil {
-		return nil, fmt.Errorf("error reaching registry endpoint %s, error: %s", challengeURL.String(), err)
+		return nil, fmt.Errorf("error reaching registry endpoint %s, error: %w", challengeURL.String(), err)
 	}
 	defer challenge.Body.Close()
 
@@ -164,7 +164,7 @@ func performTokenExchange(
 	var r *http.Request
 	r, err = http.NewRequest("POST", authEndpoint, bytes.NewBufferString(datac))
 	if err != nil {
-		return "", fmt.Errorf("failed to construct request, got %v", err)
+		return "", fmt.Errorf("failed to construct request, got %w", err)
 	}
 	r.Header.Add(userAgentHeader, userAgent)
 	r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
diff --git a/pkg/credentialprovider/azure_credentials.go b/pkg/credentialprovider/azure_credentials.go
index 593e3567b..7e4b7475e 100644
--- a/pkg/credentialprovider/azure_credentials.go
+++ b/pkg/credentialprovider/azure_credentials.go
@@ -29,12 +29,12 @@ import (
 
 	"github.com/Azure/go-autorest/autorest/adal"
 	"github.com/Azure/go-autorest/autorest/azure"
-
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/klog/v2"
 	"k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1"
-	"sigs.k8s.io/cloud-provider-azure/pkg/auth"
 	"sigs.k8s.io/yaml"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/auth"
 )
 
 // Refer: https://github.com/kubernetes/kubernetes/blob/master/pkg/credentialprovider/azure/azure_credentials.go
@@ -85,7 +85,7 @@ func newAcrProviderFromConfigReader(configReader io.Reader) (*acrProvider, error
 
 	servicePrincipalToken, err := auth.GetServicePrincipalToken(config, env, env.ServiceManagementEndpoint)
 	if err != nil {
-		return nil, fmt.Errorf("failed to create service principal token: %v", err)
+		return nil, fmt.Errorf("failed to create service principal token: %w", err)
 	}
 
 	return &acrProvider{
diff --git a/pkg/nodemanager/nodemanager.go b/pkg/nodemanager/nodemanager.go
index f7ba3abea..ec901f266 100644
--- a/pkg/nodemanager/nodemanager.go
+++ b/pkg/nodemanager/nodemanager.go
@@ -262,7 +262,7 @@ func (cnc *CloudNodeController) updateNodeAddress(ctx context.Context, node *v1.
 
 	nodeAddresses, err := cnc.getNodeAddressesByName(ctx, node)
 	if err != nil {
-		return fmt.Errorf("Error getting node addresses for node %q: %v", node.Name, err)
+		return fmt.Errorf("getting node addresses for node %q: %w", node.Name, err)
 	}
 
 	if len(nodeAddresses) == 0 {
@@ -302,7 +302,7 @@ func (cnc *CloudNodeController) updateNodeAddress(ctx context.Context, node *v1.
 	newNode.Status.Addresses = nodeAddresses
 	_, _, err = PatchNodeStatus(cnc.kubeClient.CoreV1(), types.NodeName(node.Name), node, newNode)
 	if err != nil {
-		return fmt.Errorf("Error patching node with cloud ip addresses = [%v]", err)
+		return fmt.Errorf("patching node with cloud ip addresses: %w", err)
 	}
 
 	return nil
diff --git a/pkg/provider/azure.go b/pkg/provider/azure.go
index 69de02af6..c7c2eb97c 100644
--- a/pkg/provider/azure.go
+++ b/pkg/provider/azure.go
@@ -392,7 +392,7 @@ func NewCloudFromConfigFile(configFilePath string, calFromCCM bool) (cloudprovid
 	}
 
 	if err != nil {
-		return nil, fmt.Errorf("could not init cloud provider azure: %v", err)
+		return nil, fmt.Errorf("could not init cloud provider azure: %w", err)
 	}
 	if cloud == nil {
 		return nil, fmt.Errorf("nil cloud")
@@ -436,7 +436,7 @@ func NewCloudFromSecret(clientBuilder cloudprovider.ControllerClientBuilder, sec
 
 	err := az.InitializeCloudFromSecret()
 	if err != nil {
-		return nil, fmt.Errorf("NewCloudFromSecret: failed to initialize cloud from secret %s/%s: %v", az.SecretNamespace, az.SecretName, err)
+		return nil, fmt.Errorf("NewCloudFromSecret: failed to initialize cloud from secret %s/%s: %w", az.SecretNamespace, az.SecretName, err)
 	}
 
 	az.ipv6DualStackEnabled = utilfeature.DefaultFeatureGate.Enabled(consts.IPv6DualStack)
diff --git a/pkg/provider/azure_controller_common.go b/pkg/provider/azure_controller_common.go
index dfbe8e43e..80be3c58a 100644
--- a/pkg/provider/azure_controller_common.go
+++ b/pkg/provider/azure_controller_common.go
@@ -353,7 +353,7 @@ func (c *controllerCommon) DetachDisk(ctx context.Context, diskName, diskURI str
 	} else {
 		lun, _, errGetLun := c.GetDiskLun(diskName, diskURI, nodeName)
 		if errGetLun == nil || !strings.Contains(errGetLun.Error(), consts.CannotFindDiskLUN) {
-			return fmt.Errorf("disk(%s) is still attatched to node(%s) on lun(%d), error: %v", diskURI, nodeName, lun, errGetLun)
+			return fmt.Errorf("disk(%s) is still attached to node(%s) on lun(%d), error: %w", diskURI, nodeName, lun, errGetLun)
 		}
 	}
 
diff --git a/pkg/provider/azure_instance_metadata.go b/pkg/provider/azure_instance_metadata.go
index 708804a19..014f900fb 100644
--- a/pkg/provider/azure_instance_metadata.go
+++ b/pkg/provider/azure_instance_metadata.go
@@ -23,6 +23,7 @@ import (
 	"net/http"
 
 	"k8s.io/klog/v2"
+
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 )
diff --git a/pkg/provider/azure_instances.go b/pkg/provider/azure_instances.go
index 1acd8f908..2144795a5 100644
--- a/pkg/provider/azure_instances.go
+++ b/pkg/provider/azure_instances.go
@@ -29,6 +29,7 @@ import (
 	"k8s.io/klog/v2"
 
 	"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-03-01/compute"
+
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 )
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index 3bd29159a..2e8c083d6 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -2537,7 +2537,7 @@ func (az *Cloud) reconcileSecurityGroup(clusterName string, service *v1.Service,
 
 	additionalIPs, err := getServiceAdditionalPublicIPs(service)
 	if err != nil {
-		return nil, fmt.Errorf("unable to get additional public IPs, error=%v", err)
+		return nil, fmt.Errorf("unable to get additional public IPs, error=%w", err)
 	}
 
 	destinationIPAddresses := []string{destinationIPAddress}
diff --git a/pkg/provider/azure_mock_vmsets.go b/pkg/provider/azure_mock_vmsets.go
index 648963777..88d2ab056 100644
--- a/pkg/provider/azure_mock_vmsets.go
+++ b/pkg/provider/azure_mock_vmsets.go
@@ -27,6 +27,7 @@ import (
 	v1 "k8s.io/api/core/v1"
 	types "k8s.io/apimachinery/pkg/types"
 	cloud_provider "k8s.io/cloud-provider"
+
 	cache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 )
 
diff --git a/pkg/provider/azure_standard.go b/pkg/provider/azure_standard.go
index b0d362f2f..679bf2961 100644
--- a/pkg/provider/azure_standard.go
+++ b/pkg/provider/azure_standard.go
@@ -1232,7 +1232,7 @@ func (as *availabilitySet) GetNodeNameByIPConfigurationID(ipConfigurationID stri
 
 	asName, err := getAvailabilitySetNameByID(asID)
 	if err != nil {
-		return "", "", fmt.Errorf("cannot get the availability set name by the availability set ID %s: %v", asID, err)
+		return "", "", fmt.Errorf("cannot get the availability set name by the availability set ID %s: %w", asID, err)
 	}
 	return vmName, strings.ToLower(asName), nil
 }
diff --git a/pkg/provider/azure_storageaccount.go b/pkg/provider/azure_storageaccount.go
index 3abd9d130..ba3a475b8 100644
--- a/pkg/provider/azure_storageaccount.go
+++ b/pkg/provider/azure_storageaccount.go
@@ -200,13 +200,13 @@ func (az *Cloud) EnsureStorageAccount(ctx context.Context, accountOptions *Accou
 	if accountOptions.CreatePrivateEndpoint {
 		// Create DNS zone first, this could make sure driver has write permission on vnetResourceGroup
 		if err := az.createPrivateDNSZone(ctx, vnetResourceGroup); err != nil {
-			return "", "", fmt.Errorf("Failed to create private DNS zone(%s) in resourceGroup(%s), error: %v", PrivateDNSZoneName, vnetResourceGroup, err)
+			return "", "", fmt.Errorf("Failed to create private DNS zone(%s) in resourceGroup(%s), error: %w", PrivateDNSZoneName, vnetResourceGroup, err)
 		}
 
 		// Create virtual link to the private DNS zone
 		vNetLinkName := accountName + "-vnetlink"
 		if err := az.createVNetLink(ctx, vNetLinkName, vnetResourceGroup, vnetName); err != nil {
-			return "", "", fmt.Errorf("Failed to create virtual link for vnet(%s) and DNS Zone(%s) in resourceGroup(%s), error: %v", vnetName, PrivateDNSZoneName, vnetResourceGroup, err)
+			return "", "", fmt.Errorf("Failed to create virtual link for vnet(%s) and DNS Zone(%s) in resourceGroup(%s), error: %w", vnetName, PrivateDNSZoneName, vnetResourceGroup, err)
 		}
 	}
 
@@ -306,13 +306,13 @@ func (az *Cloud) EnsureStorageAccount(ctx context.Context, accountOptions *Accou
 			// Create private endpoint
 			privateEndpointName := accountName + "-pvtendpoint"
 			if err := az.createPrivateEndpoint(ctx, accountName, storageAccount.ID, privateEndpointName, vnetResourceGroup, vnetName, subnetName, location); err != nil {
-				return "", "", fmt.Errorf("Failed to create private endpoint for storage account(%s), resourceGroup(%s), error: %v", accountName, vnetResourceGroup, err)
+				return "", "", fmt.Errorf("create private endpoint for storage account(%s), resourceGroup(%s): %w", accountName, vnetResourceGroup, err)
 			}
 
 			// Create dns zone group
 			dnsZoneGroupName := accountName + "-dnszonegroup"
 			if err := az.createPrivateDNSZoneGroup(ctx, dnsZoneGroupName, privateEndpointName, vnetResourceGroup, vnetName); err != nil {
-				return "", "", fmt.Errorf("Failed to create private DNS zone group - privateEndpoint(%s), vNetName(%s), resourceGroup(%s), error: %v", privateEndpointName, vnetName, vnetResourceGroup, err)
+				return "", "", fmt.Errorf("create private DNS zone group - privateEndpoint(%s), vNetName(%s), resourceGroup(%s): %w", privateEndpointName, vnetName, vnetResourceGroup, err)
 			}
 		}
 	}
diff --git a/pkg/provider/azure_vmss.go b/pkg/provider/azure_vmss.go
index c8f35f887..fe757963f 100644
--- a/pkg/provider/azure_vmss.go
+++ b/pkg/provider/azure_vmss.go
@@ -44,6 +44,7 @@ import (
 var (
 	// ErrorNotVmssInstance indicates an instance is not belonging to any vmss.
 	ErrorNotVmssInstance = errors.New("not a vmss instance")
+	ErrScaleSetNotFound  = errors.New("scale set not found")
 
 	scaleSetNameRE         = regexp.MustCompile(`.*/subscriptions/(?:.*)/Microsoft.Compute/virtualMachineScaleSets/(.+)/virtualMachines(?:.*)`)
 	resourceGroupRE        = regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(.+)/providers/Microsoft.Compute/virtualMachineScaleSets/(?:.*)/virtualMachines(?:.*)`)
@@ -832,7 +833,7 @@ func (ss *ScaleSet) GetVMSetNames(service *v1.Service, nodes []*v1.Node) (*[]str
 		}
 		if !found {
 			klog.Errorf("ss.GetVMSetNames - scale set (%s) in service annotation not found", serviceVMSetName)
-			return nil, fmt.Errorf("scale set (%s) - not found", serviceVMSetName)
+			return nil, ErrScaleSetNotFound
 		}
 		return &[]string{serviceVMSetName}, nil
 	}
diff --git a/pkg/retry/azure_error.go b/pkg/retry/azure_error.go
index 290faedf5..d5ddae531 100644
--- a/pkg/retry/azure_error.go
+++ b/pkg/retry/azure_error.go
@@ -352,7 +352,7 @@ func GetVMSSMetadataByRawError(err *Error) (string, string, error) {
 	reg := regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(.*)/providers/Microsoft.Compute/virtualMachineScaleSets/(.+).`)
 	matches := reg.FindStringSubmatch(err.ServiceErrorMessage())
 	if len(matches) != 3 {
-		return "", "", fmt.Errorf("GetVMSSMetadataByRawError: couldn't find a VMSS resource Id from error message %s", err.RawError)
+		return "", "", fmt.Errorf("GetVMSSMetadataByRawError: couldn't find a VMSS resource Id from error message %w", err.RawError)
 	}
 
 	return matches[1], matches[2], nil


Test patch:
diff --git a/.golangci-test.yml b/.golangci-test.yml
deleted file mode 100644
index 05efbaf64..000000000
--- a/.golangci-test.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-run:
-  deadline: 30m
-  concurrency: 2
-  go: '1.18'
-  allow-serial-runners: true
-skip-dirs:
-    - vendor
-linters:
-  disable-all: true
-  enable:
-    - gosec
-  # Run with --fast=false for more extensive checks
-  fast: false
-  govet:
-    # Report about shadowed variables.
-    # Default: false
-    check-shadowing: true
-issues:
-  exclude-rules:
-    - path: tests/e2e
-      linters:
-        - revive
-  #include:
-  #  - EXC0002 # include "missing comments" issues from golint
-  max-issues-per-linter: 0
-  max-same-issues: 0
diff --git a/cmd/cloud-controller-manager/app/options/options_test.go b/cmd/cloud-controller-manager/app/options/options_test.go
index ce705e78b..0bb3b7a47 100644
--- a/cmd/cloud-controller-manager/app/options/options_test.go
+++ b/cmd/cloud-controller-manager/app/options/options_test.go
@@ -22,10 +22,7 @@ import (
 	"testing"
 	"time"
 
-	"k8s.io/controller-manager/pkg/leadermigration/options"
-
 	"github.com/spf13/pflag"
-
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/diff"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -36,6 +33,8 @@ import (
 	componentbaseconfig "k8s.io/component-base/config"
 	kubectrlmgrconfig "k8s.io/controller-manager/config"
 	cmoptions "k8s.io/controller-manager/options"
+	"k8s.io/controller-manager/pkg/leadermigration/options"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/nodeipam/config"
 )
diff --git a/cmd/cloud-controller-manager/app/testing/testserver.go b/cmd/cloud-controller-manager/app/testing/testserver.go
index a34a22df8..a59ac8aa5 100644
--- a/cmd/cloud-controller-manager/app/testing/testserver.go
+++ b/cmd/cloud-controller-manager/app/testing/testserver.go
@@ -29,6 +29,7 @@ import (
 	"k8s.io/apimachinery/pkg/util/wait"
 	"k8s.io/client-go/kubernetes"
 	restclient "k8s.io/client-go/rest"
+
 	"sigs.k8s.io/cloud-provider-azure/cmd/cloud-controller-manager/app"
 	cloudcontrollerconfig "sigs.k8s.io/cloud-provider-azure/cmd/cloud-controller-manager/app/config"
 	"sigs.k8s.io/cloud-provider-azure/cmd/cloud-controller-manager/app/options"
diff --git a/pkg/azureclients/privateendpointclient/azure_privateendpointclient_test.go b/pkg/azureclients/privateendpointclient/azure_privateendpointclient_test.go
index 3ae8cf41f..50ef01980 100644
--- a/pkg/azureclients/privateendpointclient/azure_privateendpointclient_test.go
+++ b/pkg/azureclients/privateendpointclient/azure_privateendpointclient_test.go
@@ -26,13 +26,13 @@ import (
 	"testing"
 	"time"
 
-	"github.com/golang/mock/gomock"
-	"github.com/stretchr/testify/assert"
-
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
 	"github.com/Azure/go-autorest/autorest"
 	"github.com/Azure/go-autorest/autorest/azure"
 	"github.com/Azure/go-autorest/autorest/to"
+	"github.com/golang/mock/gomock"
+	"github.com/stretchr/testify/assert"
+
 	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient/mockarmclient"
diff --git a/pkg/azureclients/privatelinkserviceclient/azure_privatelinkserviceclient_test.go b/pkg/azureclients/privatelinkserviceclient/azure_privatelinkserviceclient_test.go
index d885b4e0b..323e6ce5d 100644
--- a/pkg/azureclients/privatelinkserviceclient/azure_privatelinkserviceclient_test.go
+++ b/pkg/azureclients/privatelinkserviceclient/azure_privatelinkserviceclient_test.go
@@ -27,12 +27,12 @@ import (
 	"testing"
 	"time"
 
+	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
+	"github.com/Azure/go-autorest/autorest"
 	"github.com/Azure/go-autorest/autorest/to"
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
 
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
-	"github.com/Azure/go-autorest/autorest"
 	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient/mockarmclient"
diff --git a/pkg/azureclients/snapshotclient/azure_snapshotclient_test.go b/pkg/azureclients/snapshotclient/azure_snapshotclient_test.go
index a82370cf2..ce1584748 100644
--- a/pkg/azureclients/snapshotclient/azure_snapshotclient_test.go
+++ b/pkg/azureclients/snapshotclient/azure_snapshotclient_test.go
@@ -31,8 +31,8 @@ import (
 	"github.com/Azure/go-autorest/autorest/to"
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
-
 	"k8s.io/client-go/util/flowcontrol"
+
 	azclients "sigs.k8s.io/cloud-provider-azure/pkg/azureclients"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/armclient/mockarmclient"
diff --git a/pkg/provider/azure_config_test.go b/pkg/provider/azure_config_test.go
index 3da00c653..f255c4bbc 100644
--- a/pkg/provider/azure_config_test.go
+++ b/pkg/provider/azure_config_test.go
@@ -23,6 +23,7 @@ import (
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 
 	"github.com/golang/mock/gomock"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/zoneclient/mockzoneclient"
 
 	"github.com/Azure/go-autorest/autorest/to"
@@ -32,8 +33,9 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	fakeclient "k8s.io/client-go/kubernetes/fake"
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/auth"
 	"sigs.k8s.io/yaml"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/auth"
 )
 
 func getTestConfig() *Config {
diff --git a/pkg/provider/azure_loadbalancer_backendpool_test.go b/pkg/provider/azure_loadbalancer_backendpool_test.go
index 0ebc64705..7b6c0bbfb 100644
--- a/pkg/provider/azure_loadbalancer_backendpool_test.go
+++ b/pkg/provider/azure_loadbalancer_backendpool_test.go
@@ -32,6 +32,7 @@ import (
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/client-go/kubernetes/fake"
 	cloudprovider "k8s.io/cloud-provider"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/loadbalancerclient/mockloadbalancerclient"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/pkg/retry"
diff --git a/pkg/provider/azure_vmss_test.go b/pkg/provider/azure_vmss_test.go
index dbfbc1415..5da4a7c65 100644
--- a/pkg/provider/azure_vmss_test.go
+++ b/pkg/provider/azure_vmss_test.go
@@ -17,6 +17,7 @@ limitations under the License.
 package provider
 
 import (
+	"errors"
 	"fmt"
 	"strings"
 	"sync"
@@ -1628,7 +1629,7 @@ func TestGetVMSetNames(t *testing.T) {
 					},
 				},
 			},
-			expectedErr: fmt.Errorf("scale set (vmss-1) - not found"),
+			expectedErr: ErrScaleSetNotFound,
 		},
 		{
 			description: "GetVMSetNames should report an error if vm's network profile is nil",
@@ -1642,7 +1643,7 @@ func TestGetVMSetNames(t *testing.T) {
 					},
 				},
 			},
-			expectedErr: fmt.Errorf("instance not found"),
+			expectedErr: cloudprovider.InstanceNotFound,
 		},
 		{
 			description: "GetVMSetNames should return the correct vmss names",
@@ -1711,7 +1712,9 @@ func TestGetVMSetNames(t *testing.T) {
 		mockVMClient.EXPECT().List(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
 
 		vmSetNames, err := ss.GetVMSetNames(test.service, test.nodes)
-		assert.Equal(t, test.expectedErr, err, test.description+", but an error occurs")
+		if test.expectedErr != nil {
+			assert.True(t, errors.Is(err, test.expectedErr), "expected error %v, got %v", test.expectedErr, err)
+		}
 		assert.Equal(t, test.expectedVMSetNames, vmSetNames, test.description)
 	}
 }
diff --git a/tests/e2e/autoscaling/autoscaler.go b/tests/e2e/autoscaling/autoscaler.go
index 31d331f33..18a3e3077 100644
--- a/tests/e2e/autoscaling/autoscaler.go
+++ b/tests/e2e/autoscaling/autoscaler.go
@@ -25,16 +25,16 @@ import (
 	"strings"
 	"time"
 
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
 	appsv1 "k8s.io/api/apps/v1"
 	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/wait"
 	clientset "k8s.io/client-go/kubernetes"
-	"sigs.k8s.io/cloud-provider-azure/tests/e2e/utils"
 
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
+	"sigs.k8s.io/cloud-provider-azure/tests/e2e/utils"
 )
 
 const (
diff --git a/tests/e2e/network/node.go b/tests/e2e/network/node.go
index 45e825b0b..88b7064e8 100644
--- a/tests/e2e/network/node.go
+++ b/tests/e2e/network/node.go
@@ -28,11 +28,11 @@ import (
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
-
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	clientset "k8s.io/client-go/kubernetes"
+
 	"sigs.k8s.io/cloud-provider-azure/tests/e2e/utils"
 )
 
diff --git a/tests/e2e/network/private_link_service.go b/tests/e2e/network/private_link_service.go
index 5278bfdfd..cbb1f60bb 100644
--- a/tests/e2e/network/private_link_service.go
+++ b/tests/e2e/network/private_link_service.go
@@ -24,18 +24,18 @@ import (
 	"strings"
 	"time"
 
+	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
+	"github.com/Azure/go-autorest/autorest/to"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/apimachinery/pkg/util/wait"
 	clientset "k8s.io/client-go/kubernetes"
+
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
 	"sigs.k8s.io/cloud-provider-azure/tests/e2e/utils"
-
-	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
-	"github.com/Azure/go-autorest/autorest/to"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
 )
 
 var _ = Describe("Private link service", Label(utils.TestSuiteLabelPrivateLinkService), func() {
diff --git a/tests/e2e/network/service_annotations.go b/tests/e2e/network/service_annotations.go
index 91369d128..fe7665d3a 100644
--- a/tests/e2e/network/service_annotations.go
+++ b/tests/e2e/network/service_annotations.go
@@ -711,10 +711,9 @@ var _ = Describe("Service with annotation", Label(utils.TestSuiteLabelServiceAnn
 		pipName := fmt.Sprintf("%s-public-IP%s", basename, string(uuid.NewUUID())[0:4])
 		By(fmt.Sprintf("Creating a public IP %q", pipName))
 		var pip network.PublicIPAddress
+		// TODO: dual-stack support
 		if tc.IPFamily != utils.DualStack {
 			pip = defaultPublicIPAddress(pipName, tc.IPFamily == utils.IPv6)
-		} else {
-			// TODO: dual-stack support
 		}
 		rg := tc.GetResourceGroup()
 		pip, err := utils.WaitCreatePIP(tc, pipName, rg, pip)
@@ -728,12 +727,11 @@ var _ = Describe("Service with annotation", Label(utils.TestSuiteLabelServiceAnn
 		utils.Logf("Created pip with address %s", pipAddr)
 
 		annotation := map[string]string{}
+		// TODO: dual-stack support
 		if tc.IPFamily == utils.IPv4 {
 			annotation[consts.ServiceAnnotationLoadBalancerIPDualStack[false]] = pipAddr
 		} else if tc.IPFamily == utils.IPv6 {
 			annotation[consts.ServiceAnnotationLoadBalancerIPDualStack[true]] = pipAddr
-		} else {
-			// TODO: dual-stack support
 		}
 
 		By("Creating a Service")
diff --git a/tests/e2e/network/standard_lb.go b/tests/e2e/network/standard_lb.go
index 6e2838e54..606d81ab2 100644
--- a/tests/e2e/network/standard_lb.go
+++ b/tests/e2e/network/standard_lb.go
@@ -23,14 +23,13 @@ import (
 
 	azcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-03-01/compute"
 	"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-08-01/network"
-
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
-
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	clientset "k8s.io/client-go/kubernetes"
+
 	"sigs.k8s.io/cloud-provider-azure/tests/e2e/utils"
 )
 
diff --git a/tests/e2e/utils/ip_utils.go b/tests/e2e/utils/ip_utils.go
index 5d13fe111..0f79e32e9 100644
--- a/tests/e2e/utils/ip_utils.go
+++ b/tests/e2e/utils/ip_utils.go
@@ -89,13 +89,13 @@ func getNextSubnet(vnetCIDR string, existSubnets []string) (*net.IPNet, error) {
 	// IPv4
 	intIPArray, vNetMask, err := cidrString2intArray(vnetCIDR)
 	if err != nil {
-		return nil, fmt.Errorf("unexpected vnet address CIDR: %v", err)
+		return nil, fmt.Errorf("unexpected vnet address CIDR: %w", err)
 	}
 	root := initIPTreeRoot(vNetMask)
 	for _, subnet := range existSubnetsWithSameIPFamily {
 		subnetIPArray, subnetPrefix, err := cidrString2intArray(subnet)
 		if err != nil {
-			return nil, fmt.Errorf("unexpected subnet address prefix: %v", err)
+			return nil, fmt.Errorf("unexpected subnet address prefix: %w", err)
 		}
 		setOccupiedByPrefix(root, subnetIPArray, subnetPrefix)
 	}
diff --git a/tests/e2e/utils/kubectl.go b/tests/e2e/utils/kubectl.go
index 79303a5a5..906a3d1cb 100644
--- a/tests/e2e/utils/kubectl.go
+++ b/tests/e2e/utils/kubectl.go
@@ -18,6 +18,7 @@ package utils
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"net"
 	"net/url"
@@ -157,8 +158,9 @@ func (b KubectlBuilder) ExecWithFullOutput(print bool) (string, string, error) {
 	case err := <-errCh:
 		if err != nil {
 			var rc = 127
-			if ee, ok := err.(*exec.ExitError); ok {
-				rc = ee.Sys().(syscall.WaitStatus).ExitStatus()
+			var exitError *exec.ExitError
+			if errors.As(err, &exitError) {
+				rc = exitError.Sys().(syscall.WaitStatus).ExitStatus()
 				Logf("rc: %d", rc)
 			}
 			return stdout.String(), stderr.String(), uexec.CodeExitError{
@@ -178,16 +180,17 @@ func (b KubectlBuilder) ExecWithFullOutput(print bool) (string, string, error) {
 }
 
 func isTimeout(err error) bool {
-	switch err := err.(type) {
-	case *url.Error:
-		if err, ok := err.Err.(net.Error); ok && err.Timeout() {
-			return true
-		}
-	case net.Error:
-		if err.Timeout() {
-			return true
-		}
+	var (
+		urlError *url.Error
+		netError net.Error
+	)
+	if errors.As(err, &urlError) {
+		err = urlError.Err
 	}
+	if errors.As(err, &netError) {
+		return netError.Timeout()
+	}
+
 	return false
 }
 
diff --git a/tests/e2e/utils/network_utils.go b/tests/e2e/utils/network_utils.go
index a2b57bf57..4b5588704 100644
--- a/tests/e2e/utils/network_utils.go
+++ b/tests/e2e/utils/network_utils.go
@@ -18,6 +18,7 @@ package utils
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net"
 	"os"
@@ -145,7 +146,7 @@ func GetNextSubnetCIDR(vnet aznetwork.VirtualNetwork, ipFamily IPFamily) (*net.I
 			addrPrefix := (*vnet.AddressSpace.AddressPrefixes)[i]
 			ip, _, err := net.ParseCIDR(addrPrefix)
 			if err != nil {
-				return nil, fmt.Errorf("failed to parse address prefix CIDR: %v", err)
+				return nil, fmt.Errorf("failed to parse address prefix CIDR: %w", err)
 			}
 			if ip.To4() == nil {
 				vnetCIDR = addrPrefix
@@ -211,7 +212,7 @@ func (azureTestClient *AzureTestClient) GetClusterSecurityGroups() (ret []aznetw
 		}
 		return false, nil
 	})
-	if err == wait.ErrWaitTimeout {
+	if errors.Is(err, wait.ErrWaitTimeout) {
 		err = fmt.Errorf("could not find the cluster security group in resource group %s", azureTestClient.GetResourceGroup())
 	}
 	return
@@ -327,7 +328,7 @@ func WaitGetPIPByPrefix(
 			}
 			Logf("prefix = [%s] not ready with error = [%v] and number of IP = [%d]", prefixName, err, numOfIPs)
 			if !untilPIPCreated {
-				return true, fmt.Errorf("get pip by prefix = [%s], err = [%v], number of IP = [%d]", prefixName, err, numOfIPs)
+				return true, fmt.Errorf("get pip by prefix = [%s], err = [%w], number of IP = [%d]", prefixName, err, numOfIPs)
 			}
 			return false, nil
 		}
@@ -548,7 +549,7 @@ func retrieveCIDRs(cmd string, reg string) ([]string, error) {
 	res := make([]string, 2)
 	stdout, err := RunKubectlNoPrint("", strings.Split(cmd, " ")...)
 	if err != nil {
-		return res, fmt.Errorf("error when running the following kubectl command %q: %v, %s", cmd, err, stdout)
+		return res, fmt.Errorf("error when running the following kubectl command %q: %w, %s", cmd, err, stdout)
 	}
 	re := regexp.MustCompile(reg)
 	matches := re.FindStringSubmatch(stdout)
diff --git a/tests/e2e/utils/pod_utils.go b/tests/e2e/utils/pod_utils.go
index d6be62acd..cc33d2ce3 100644
--- a/tests/e2e/utils/pod_utils.go
+++ b/tests/e2e/utils/pod_utils.go
@@ -18,6 +18,7 @@ package utils
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"regexp"
 	"time"
@@ -87,7 +88,7 @@ func WaitPodsToBeReady(cs clientset.Interface, ns string) error {
 		return pendingPodCount == 0, nil
 	})
 	if err != nil {
-		if err == wait.ErrWaitTimeout {
+		if errors.Is(err, wait.ErrWaitTimeout) {
 			for _, pod := range pods {
 				printPodInfo(cs, ns, pod.Name)
 			}
@@ -208,7 +209,7 @@ func GetPod(cs clientset.Interface, ns, name string) (pod *v1.Pod, err error) {
 			return false, err
 		}
 		return true, nil
-	}); pollErr == wait.ErrWaitTimeout {
+	}); errors.Is(pollErr, wait.ErrWaitTimeout) {
 		return nil, fmt.Errorf("failed to get Pod %q in namespace %q", name, ns)
 	}
 	return pod, err
@@ -291,7 +292,7 @@ func GetPodOutboundIP(cs clientset.Interface, podTemplate *v1.Pod, nsName string
 		return PodIPRE.MatchString(string(log)), nil
 	})
 	if err != nil {
-		if err == wait.ErrWaitTimeout {
+		if errors.Is(err, wait.ErrWaitTimeout) {
 			printPodInfo(cs, nsName, podTemplate.Name)
 		}
 		return "", err
diff --git a/tests/e2e/utils/service_utils.go b/tests/e2e/utils/service_utils.go
index 0783333b8..ba413b6e5 100644
--- a/tests/e2e/utils/service_utils.go
+++ b/tests/e2e/utils/service_utils.go
@@ -115,7 +115,7 @@ func WaitServiceExposureAndValidateConnectivity(cs clientset.Interface, namespac
 		}
 	}()
 	if !result || err != nil {
-		return "", fmt.Errorf("failed to create ExecAgnhostPod, result: %v, error: %v", result, err)
+		return "", fmt.Errorf("failed to create ExecAgnhostPod, result: %v, error: %w", result, err)
 	}
 
 	// TODO: Check if other WaitServiceExposureAndValidateConnectivity() callers with internal Service