diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2436478..eca215f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -39,15 +39,6 @@ jobs: run: | make test git status - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3.1.4 - with: - flags: unittests - file: cover.out - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - name: Check diff - run: '[[ -z $(git status -s) ]] || (printf "Existing modified/untracked files.\nPlease run \"make generate manifests fmt vet\" and push again.\n"; exit 1)' GolangLint: name: Golang Lint diff --git a/.licenserc.yaml b/.licenserc.yaml new file mode 100644 index 0000000..3873559 --- /dev/null +++ b/.licenserc.yaml @@ -0,0 +1,64 @@ +header: + license: + content: | + 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. + paths: + - '**' + paths-ignore: + - '**/*.conf' + - '**/*.DS_Store' + - '**/*.json' + - '**/*.lock' + - '**/*.Dockerfile' + - '**/*.sh' + - '**/*.yaml' + - '**/*.md' + - '**/*.mk' + - '**/*.svg' + - '**/*.txt' + - '**/*.xlf' + - '**/.husky/**' + - '**/node_modules/**' + - '**/.babelrc' + - '**/.browserslistrc' + - '**/.editorconfig' + - '**/.jsbeautifyrc' + - '**/.yarnrc.yml' + - '**/config_repos' + - '**/go.mod' + - '**/go.sum' + - '**/go.work' + - '**/go.work.sum' + - '**/lcov.info' + - '**/Makefile' + - '**/OWNERS' + - '.github/**' + - '.idea/**' + - '.vscode/**' + - '.dist/**' + - '.husky/**' + - 'hack/**' + - 'LICENSE' + - 'OWNERS_ALIASES' + - 'SECURITY_CONTACTS' + - 'vendor/**' + - '.gitignore' + - '.licenserc' + - '**/zz_generated.deepcopy.go' + - '**/*.pb.go' + - '**/*.proto' + - '**/PROJECT' + - '**/Dockerfile' + - '**/.dockerignore' + comment: never + license-location-threshold: 80 \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f3cd1e2 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. +ENVTEST_K8S_VERSION = 1.22.1 + +.PHONY: fmt +fmt: ## Run go fmt against code. + go fmt ./... + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test +test: fmt vet envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out + +##@ Build Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +ENVTEST ?= $(LOCALBIN)/setup-envtest + +.PHONY: envtest +envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. +$(ENVTEST): $(LOCALBIN) + test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest \ No newline at end of file diff --git a/cache/cache_test.go b/cache/cache_test.go index f820a7c..8209dff 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -36,7 +36,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" ) const ( @@ -45,11 +44,13 @@ const ( ) var ( - env *envtest.Environment - mgr manager.Manager - request chan reconcile.Request - pod *corev1.Pod - deploy *appsv1.Deployment + env *envtest.Environment + mgr manager.Manager + ctx context.Context + cancel context.CancelFunc + + pod *corev1.Pod + deploy *appsv1.Deployment c client.Client ) @@ -58,11 +59,11 @@ var _ = Describe("cache support no DeepCopy", func() { It("support list without DeepCopy", func() { podListNoDeepCopy1 := &corev1.PodList{} - Expect(c.List(context.TODO(), podListNoDeepCopy1, DisableDeepCopy)).Should(BeNil()) + Expect(c.List(ctx, podListNoDeepCopy1, DisableDeepCopy)).Should(BeNil()) podListNoDeepCopy2 := &corev1.PodList{} - Expect(c.List(context.TODO(), podListNoDeepCopy2, DisableDeepCopy)).Should(BeNil()) + Expect(c.List(ctx, podListNoDeepCopy2, DisableDeepCopy)).Should(BeNil()) podListDeepCopy := &corev1.PodList{} - Expect(c.List(context.TODO(), podListDeepCopy)).Should(BeNil()) + Expect(c.List(ctx, podListDeepCopy)).Should(BeNil()) Expect(podListNoDeepCopy1.Items[0]).Should(BeEquivalentTo(podListNoDeepCopy2.Items[0])) Expect(podListNoDeepCopy1.Items[0]).ShouldNot(BeEquivalentTo(podListDeepCopy.Items[0])) @@ -73,11 +74,11 @@ var _ = Describe("cache support no DeepCopy", func() { FieldSelector: fields.AndSelectors(fields.OneTermEqualSelector(TestPodNamespaceFieldIndex, pod.Namespace), fields.OneTermEqualSelector(TestPodContainerNumberFieldIndex, fmt.Sprintf("%d", len(pod.Spec.Containers))))} podListNoDeepCopy1 := &corev1.PodList{} - Expect(c.List(context.TODO(), podListNoDeepCopy1, DisableDeepCopy, fieldIndexOption)).Should(BeNil()) + Expect(c.List(ctx, podListNoDeepCopy1, DisableDeepCopy, fieldIndexOption)).Should(BeNil()) podListNoDeepCopy2 := &corev1.PodList{} - Expect(c.List(context.TODO(), podListNoDeepCopy2, DisableDeepCopy, fieldIndexOption)).Should(BeNil()) + Expect(c.List(ctx, podListNoDeepCopy2, DisableDeepCopy, fieldIndexOption)).Should(BeNil()) podListDeepCopy := &corev1.PodList{} - Expect(c.List(context.TODO(), podListDeepCopy)).Should(BeNil()) + Expect(c.List(ctx, podListDeepCopy)).Should(BeNil()) Expect(podListNoDeepCopy1.Items[0]).Should(BeEquivalentTo(podListNoDeepCopy2.Items[0])) Expect(podListNoDeepCopy1.Items[0]).ShouldNot(BeEquivalentTo(podListDeepCopy.Items[0])) @@ -85,11 +86,11 @@ var _ = Describe("cache support no DeepCopy", func() { It("support get without DeepCopy", func() { podWithoutDeepCopy1 := &ObjectWithoutDeepCopy{Object: &corev1.Pod{}} - Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, podWithoutDeepCopy1)).Should(BeNil()) + Expect(c.Get(ctx, types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, podWithoutDeepCopy1)).Should(BeNil()) podWithoutDeepCopy2 := &ObjectWithoutDeepCopy{Object: &corev1.Pod{}} - Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, podWithoutDeepCopy2)).Should(BeNil()) + Expect(c.Get(ctx, types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, podWithoutDeepCopy2)).Should(BeNil()) podWithDeepCopy := &corev1.Pod{} - Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, podWithDeepCopy)).Should(BeNil()) + Expect(c.Get(ctx, types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, podWithDeepCopy)).Should(BeNil()) Expect(podWithoutDeepCopy1.Object.(*corev1.Pod).Spec.Containers[0].ReadinessProbe).ShouldNot(BeNil()) Expect(podWithoutDeepCopy2.Object.(*corev1.Pod).Spec.Containers[0].ReadinessProbe).ShouldNot(BeNil()) @@ -97,16 +98,16 @@ var _ = Describe("cache support no DeepCopy", func() { Expect(podWithoutDeepCopy1.Object.(*corev1.Pod).Spec.Containers[0].ReadinessProbe == podWithoutDeepCopy2.Object.(*corev1.Pod).Spec.Containers[0].ReadinessProbe).Should(BeTrue()) Expect(podWithoutDeepCopy1.Object.(*corev1.Pod).Spec.Containers[0].ReadinessProbe == podWithDeepCopy.Spec.Containers[0].ReadinessProbe).Should(BeFalse()) - Expect(errors.IsNotFound(c.Get(context.TODO(), types.NamespacedName{Namespace: pod.Namespace, Name: "not-found"}, podWithoutDeepCopy1))).Should(BeTrue()) + Expect(errors.IsNotFound(c.Get(ctx, types.NamespacedName{Namespace: pod.Namespace, Name: "not-found"}, podWithoutDeepCopy1))).Should(BeTrue()) }) It("support uncached object", func() { deployUncached0 := &ObjectWithoutDeepCopy{Object: &appsv1.Deployment{}} - Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deployUncached0)).ShouldNot(BeNil()) + Expect(c.Get(ctx, types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deployUncached0)).ShouldNot(BeNil()) deployUncached1 := &appsv1.Deployment{} - Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deployUncached1)).Should(BeNil()) + Expect(c.Get(ctx, types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deployUncached1)).Should(BeNil()) deployUncached2 := &appsv1.Deployment{} - Expect(c.Get(context.TODO(), types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deployUncached2)).Should(BeNil()) + Expect(c.Get(ctx, types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deployUncached2)).Should(BeNil()) Expect(deployUncached1.Spec.Selector).ShouldNot(BeNil()) Expect(deployUncached2.Spec.Selector).ShouldNot(BeNil()) @@ -114,8 +115,8 @@ var _ = Describe("cache support no DeepCopy", func() { }) }) -func initPod() *corev1.Pod { - pod := &corev1.Pod{ +func initPod() { + pod = &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "foo", @@ -137,16 +138,14 @@ func initPod() *corev1.Pod { }, }, } - Expect(c.Create(context.TODO(), pod)).Should(BeNil()) + Expect(c.Create(ctx, pod)).Should(BeNil()) Eventually(func() bool { - return c.Get(context.TODO(), types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, pod) == nil + return c.Get(ctx, types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, pod) == nil }, 5*time.Second, 1*time.Second).Should(BeTrue()) - - return pod } -func initDeploy() *appsv1.Deployment { - deploy := &appsv1.Deployment{ +func initDeploy() { + deploy = &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "foo", @@ -174,12 +173,10 @@ func initDeploy() *appsv1.Deployment { }, }, } - Expect(c.Create(context.TODO(), deploy)).Should(BeNil()) + Expect(c.Create(ctx, deploy)).Should(BeNil()) Eventually(func() bool { - return c.Get(context.TODO(), types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deploy) == nil + return c.Get(ctx, types.NamespacedName{Namespace: deploy.Namespace, Name: deploy.Name}, deploy) == nil }, 5*time.Second, 1*time.Second).Should(BeTrue()) - - return deploy } func TestCache(t *testing.T) { @@ -197,6 +194,8 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) Expect(config).NotTo(BeNil()) + ctx, cancel = context.WithCancel(context.Background()) + mgr, err = manager.New(config, manager.Options{ MetricsBindAddress: "0", NewCache: NewCacheSupportDisableDeepCopy, @@ -207,25 +206,26 @@ var _ = BeforeSuite(func() { c = mgr.GetClient() c := mgr.GetCache() - c.IndexField(context.TODO(), &corev1.Pod{}, TestPodNamespaceFieldIndex, func(obj client.Object) []string { - pod := obj.(*corev1.Pod) - return []string{pod.Namespace} + c.IndexField(ctx, &corev1.Pod{}, TestPodNamespaceFieldIndex, func(obj client.Object) []string { + po := obj.(*corev1.Pod) + return []string{po.Namespace} }) - c.IndexField(context.TODO(), &corev1.Pod{}, TestPodContainerNumberFieldIndex, func(obj client.Object) []string { - pod := obj.(*corev1.Pod) - return []string{fmt.Sprintf("%d", len(pod.Spec.Containers))} + c.IndexField(ctx, &corev1.Pod{}, TestPodContainerNumberFieldIndex, func(obj client.Object) []string { + po := obj.(*corev1.Pod) + return []string{fmt.Sprintf("%d", len(po.Spec.Containers))} }) go func() { - err = mgr.Start(context.TODO()) + err = mgr.Start(ctx) Expect(err).NotTo(HaveOccurred()) }() - pod = initPod() - deploy = initDeploy() + initPod() + initDeploy() }) var _ = AfterSuite(func() { + cancel() By("tearing down the test environment") Expect(env.Stop()).NotTo(HaveOccurred()) diff --git a/controller/mixin/webhook_test.go b/controller/mixin/webhook_test.go index 4344677..36233fc 100644 --- a/controller/mixin/webhook_test.go +++ b/controller/mixin/webhook_test.go @@ -33,6 +33,7 @@ func TestNewWebhookHandlerMixin(t *testing.T) { MapperProvider: func(c *rest.Config) (meta.RESTMapper, error) { return apiutil.NewDynamicRESTMapper(c, apiutil.WithLazyDiscovery) }, + MetricsBindAddress: "0", }) assert.Nil(t, err) diff --git a/controller/workqueue/priority_queue.go b/controller/workqueue/priority_queue.go index 64d7522..2402d16 100644 --- a/controller/workqueue/priority_queue.go +++ b/controller/workqueue/priority_queue.go @@ -282,7 +282,6 @@ func (q *PriorityQueue) Done(item interface{}) { q.processing.delete(item) if q.dirty.has(item) { - q.priorityQueue[priority] = append(q.priorityQueue[priority], item) q.count++ klog.V(5).Infof("Add item to priority queue from dirty, priority: %v, count: %v", priority, q.count) diff --git a/controller/workqueue/suite_test.go b/controller/workqueue/suite_test.go index 5d944f7..fa75918 100644 --- a/controller/workqueue/suite_test.go +++ b/controller/workqueue/suite_test.go @@ -1,3 +1,19 @@ +/** + * Copyright 2024 KusionStack 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. + */ + package workqueue import ( diff --git a/multicluster/help_test.go b/multicluster/help_test.go index 84f53f3..710481b 100644 --- a/multicluster/help_test.go +++ b/multicluster/help_test.go @@ -134,8 +134,8 @@ var _ = Describe("help", func() { podList, ok := podListObj.(*corev1.PodList) Expect(ok).To(BeTrue()) for _, pod := range podList.Items { - cluster, ok := pod.GetLabels()[clusterinfo.ClusterLabelKey] - Expect(ok).To(BeTrue()) + cluster, ok1 := pod.GetLabels()[clusterinfo.ClusterLabelKey] + Expect(ok1).To(BeTrue()) Expect(cluster).To(Equal("cluster1")) } diff --git a/multicluster/manager_test.go b/multicluster/manager_test.go index 087fa0b..0528a54 100644 --- a/multicluster/manager_test.go +++ b/multicluster/manager_test.go @@ -453,8 +453,9 @@ var _ = Describe("multicluster with 1 fed and 4 clusters", func() { }) func newMockClient() *MockClient { + clientBuilder := fake.NewClientBuilder() return &MockClient{ - WithWatch: fake.NewFakeClient(), + WithWatch: clientBuilder.Build(), } } diff --git a/multicluster/multi_cluster_cache.go b/multicluster/multi_cluster_cache.go index 08fc83a..77234bf 100644 --- a/multicluster/multi_cluster_cache.go +++ b/multicluster/multi_cluster_cache.go @@ -570,16 +570,20 @@ func (mci *multiClusterInformer) addClusterInformer(cluster string, clusterInfor mci.mutex.Lock() defer mci.mutex.Unlock() + if mci.indexers != nil { + err := clusterInformer.AddIndexers(mci.indexers) + if err != nil { + mci.log.Error(err, "failed to add indexer", "cluster", cluster) + return + } + } + if mci.handler != nil && mci.resyncPeriod != 0 { clusterInformer.AddEventHandlerWithResyncPeriod(mci.handler, mci.resyncPeriod) } else if mci.handler != nil { clusterInformer.AddEventHandler(mci.handler) } - if mci.indexers != nil { - clusterInformer.AddIndexers(mci.indexers) - } - mci.clusterToInformer[cluster] = clusterInformer }