Merge pull request #228 from sjmshsh/master
validator and mutator
diff --git a/api/system/v1alpha1/zone_insight_helpers.go b/api/system/v1alpha1/zone_insight_helpers.go
new file mode 100644
index 0000000..9aa529b
--- /dev/null
+++ b/api/system/v1alpha1/zone_insight_helpers.go
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 v1alpha1
+
+func (x *ZoneInsight) IsOnline() bool {
+ for _, s := range x.GetSubscriptions() {
+ if s.ConnectTime != nil && s.DisconnectTime == nil {
+ return true
+ }
+ }
+ return false
+}
diff --git a/pkg/core/bootstrap/bootstrap.go b/pkg/core/bootstrap/bootstrap.go
index 9ead6a1..ca34cf6 100644
--- a/pkg/core/bootstrap/bootstrap.go
+++ b/pkg/core/bootstrap/bootstrap.go
@@ -19,6 +19,8 @@
import (
"context"
+ "github.com/apache/dubbo-kubernetes/pkg/core/managers/apis/zone"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/apis/system"
k8s_extensions "github.com/apache/dubbo-kubernetes/pkg/plugins/extensions/k8s"
"net/http"
"net/url"
@@ -454,6 +456,13 @@
),
)
+ customizableManager.Customize(
+ system.ZoneType,
+ zone.NewZoneManager(builder.ResourceStore(),
+ zone.Validator{Store: builder.ResourceStore()},
+ builder.Config().Store.UnsafeDelete,
+ ))
+
builder.WithResourceManager(customizableManager)
if builder.Config().Store.Cache.Enabled {
diff --git a/pkg/core/managers/apis/zone/zone_manager.go b/pkg/core/managers/apis/zone/zone_manager.go
new file mode 100644
index 0000000..fd59f02
--- /dev/null
+++ b/pkg/core/managers/apis/zone/zone_manager.go
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 zone
+
+import (
+ "context"
+ core_manager "github.com/apache/dubbo-kubernetes/pkg/core/resources/manager"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/model"
+ core_store "github.com/apache/dubbo-kubernetes/pkg/core/resources/store"
+)
+
+func NewZoneManager(store core_store.ResourceStore, validator Validator, unsafeDelete bool) core_manager.ResourceManager {
+ return &zoneManager{
+ ResourceManager: core_manager.NewResourceManager(store),
+ store: store,
+ validator: validator,
+ unsafeDelete: unsafeDelete,
+ }
+}
+
+type zoneManager struct {
+ core_manager.ResourceManager
+ store core_store.ResourceStore
+ validator Validator
+ unsafeDelete bool
+}
+
+func (z *zoneManager) Delete(ctx context.Context, r model.Resource, opts ...core_store.DeleteOptionsFunc) error {
+ options := core_store.NewDeleteOptions(opts...)
+ if !z.unsafeDelete {
+ if err := z.validator.ValidateDelete(ctx, options.Name); err != nil {
+ return err
+ }
+ }
+ return z.ResourceManager.Delete(ctx, r, opts...)
+}
diff --git a/pkg/core/managers/apis/zone/zone_manager_suite_test.go b/pkg/core/managers/apis/zone/zone_manager_suite_test.go
new file mode 100644
index 0000000..58564df
--- /dev/null
+++ b/pkg/core/managers/apis/zone/zone_manager_suite_test.go
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 zone_test
+
+import (
+ "context"
+ "github.com/apache/dubbo-kubernetes/api/system/v1alpha1"
+ "github.com/apache/dubbo-kubernetes/pkg/util/proto"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "github.com/apache/dubbo-kubernetes/pkg/core/managers/apis/zone"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/apis/system"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/model"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/store"
+ "github.com/apache/dubbo-kubernetes/pkg/plugins/resources/memory"
+)
+
+var _ = Describe("Zone Manager", func() {
+ var validator zone.Validator
+ var resStore store.ResourceStore
+
+ BeforeEach(func() {
+ resStore = memory.NewStore()
+ validator = zone.Validator{Store: resStore}
+ })
+
+ It("should not delete zone if it's online", func() {
+ // given zone and zoneInsight
+ err := resStore.Create(context.Background(), system.NewZoneResource(), store.CreateByKey("zone-1", model.NoMesh))
+ Expect(err).ToNot(HaveOccurred())
+
+ err = resStore.Create(context.Background(), &system.ZoneInsightResource{
+ Spec: &v1alpha1.ZoneInsight{
+ Subscriptions: []*v1alpha1.DDSSubscription{
+ {
+ ConnectTime: proto.MustTimestampProto(time.Now()),
+ },
+ },
+ },
+ }, store.CreateByKey("zone-1", model.NoMesh))
+ Expect(err).ToNot(HaveOccurred())
+ zoneManager := zone.NewZoneManager(resStore, validator, false)
+
+ zone := system.NewZoneResource()
+ err = resStore.Get(context.Background(), zone, store.GetByKey("zone-1", model.NoMesh))
+ Expect(err).ToNot(HaveOccurred())
+
+ // when
+ err = zoneManager.Delete(context.Background(), zone, store.DeleteByKey("zone-1", model.NoMesh))
+
+ // then
+ Expect(err).To(HaveOccurred())
+ Expect(err.Error()).To(ContainSubstring("zone: unable to delete Zone, Zone CP is still connected, please shut it down first"))
+ })
+
+ It("should delete if zone is online when unsafe delete is enabled", func() {
+ // given zone and zoneInsight
+ err := resStore.Create(context.Background(), system.NewZoneResource(), store.CreateByKey("zone-1", model.NoMesh))
+ Expect(err).ToNot(HaveOccurred())
+
+ err = resStore.Create(context.Background(), &system.ZoneInsightResource{
+ Spec: &v1alpha1.ZoneInsight{
+ Subscriptions: []*v1alpha1.DDSSubscription{
+ {
+ ConnectTime: proto.MustTimestampProto(time.Now()),
+ },
+ },
+ },
+ }, store.CreateByKey("zone-1", model.NoMesh))
+ Expect(err).ToNot(HaveOccurred())
+ zoneManager := zone.NewZoneManager(resStore, validator, true)
+
+ zone := system.NewZoneResource()
+ err = resStore.Get(context.Background(), zone, store.GetByKey("zone-1", model.NoMesh))
+ Expect(err).ToNot(HaveOccurred())
+
+ // when
+ err = zoneManager.Delete(context.Background(), zone, store.DeleteByKey("zone-1", model.NoMesh))
+
+ // then
+ Expect(err).ToNot(HaveOccurred())
+ })
+})
diff --git a/pkg/core/managers/apis/zone/zone_manager_test.go b/pkg/core/managers/apis/zone/zone_manager_test.go
new file mode 100644
index 0000000..daf8e7d
--- /dev/null
+++ b/pkg/core/managers/apis/zone/zone_manager_test.go
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 zone_test
+
+import (
+ "github.com/apache/dubbo-kubernetes/pkg/test"
+ "testing"
+)
+
+func TestZoneManager(t *testing.T) {
+ test.RunSpecs(t, "Zone Manager Suite")
+}
diff --git a/pkg/core/managers/apis/zone/zone_validator.go b/pkg/core/managers/apis/zone/zone_validator.go
new file mode 100644
index 0000000..bf1df3a
--- /dev/null
+++ b/pkg/core/managers/apis/zone/zone_validator.go
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 zone
+
+import (
+ "context"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/apis/system"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/model"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/store"
+ "github.com/apache/dubbo-kubernetes/pkg/core/validators"
+ "github.com/pkg/errors"
+)
+
+type Validator struct {
+ Store store.ResourceStore
+}
+
+func (v *Validator) ValidateDelete(ctx context.Context, name string) error {
+ zi := system.NewZoneInsightResource()
+ validationErr := &validators.ValidationError{}
+ if err := v.Store.Get(ctx, zi, store.GetByKey(name, model.NoMesh)); err != nil {
+ if store.IsResourceNotFound(err) {
+ return nil
+ }
+ return errors.Wrap(err, "unable to get ZoneInsight")
+ }
+ if zi.Spec.IsOnline() {
+ validationErr.AddViolation("zone", "unable to delete Zone, Zone CP is still connected, please shut it down first")
+ return validationErr
+ }
+ return nil
+}
diff --git a/pkg/plugins/runtime/k8s/plugin.go b/pkg/plugins/runtime/k8s/plugin.go
index 70b9e2f..93732af 100644
--- a/pkg/plugins/runtime/k8s/plugin.go
+++ b/pkg/plugins/runtime/k8s/plugin.go
@@ -18,6 +18,7 @@
package k8s
import (
+ "github.com/apache/dubbo-kubernetes/pkg/core/managers/apis/zone"
"github.com/pkg/errors"
kube_ctrl "sigs.k8s.io/controller-runtime"
@@ -113,6 +114,18 @@
handler := k8s_webhooks.NewValidatingWebhook(converter, core_registry.Global(), k8s_registry.Global(), rt.Config().Mode, rt.Config().IsFederatedZoneCP(), rt.Config().Multizone.Zone.DisableOriginLabelValidation)
composite.AddValidator(handler)
+ coreZoneValidator := zone.Validator{Store: rt.ResourceManager()}
+ k8sZoneValidator := k8s_webhooks.NewZoneValidatorWebhook(coreZoneValidator, rt.Config().Store.UnsafeDelete)
+ composite.AddValidator(k8sZoneValidator)
+
+ composite.AddValidator(&k8s_webhooks.PolicyNamespaceValidator{
+ SystemNamespace: rt.Config().Store.Kubernetes.SystemNamespace,
+ })
+
+ composite.AddValidator(&k8s_webhooks.ContainerPatchValidator{
+ SystemNamespace: rt.Config().Store.Kubernetes.SystemNamespace,
+ })
+
mgr.GetWebhookServer().Register("/validate-dubbo-io-v1alpha1", composite.IntoWebhook(mgr.GetScheme()))
return nil
diff --git a/pkg/plugins/runtime/k8s/webhooks/containerpatch_validator.go b/pkg/plugins/runtime/k8s/webhooks/containerpatch_validator.go
new file mode 100644
index 0000000..2fb28af
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/webhooks/containerpatch_validator.go
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 webhooks
+
+import (
+ "context"
+ k8s_common "github.com/apache/dubbo-kubernetes/pkg/plugins/common/k8s"
+ mesh_k8s "github.com/apache/dubbo-kubernetes/pkg/plugins/resources/k8s/native/api/v1alpha1"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+type ContainerPatchValidator struct {
+ SystemNamespace string
+}
+
+func NewContainerPatchValidatorWebhook() k8s_common.AdmissionValidator {
+ return &ContainerPatchValidator{}
+}
+
+func (h *ContainerPatchValidator) InjectDecoder(d *admission.Decoder) {
+}
+
+func (h *ContainerPatchValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
+ if req.Namespace != h.SystemNamespace {
+ return admission.Denied("ContainerPatch can only be placed in " + h.SystemNamespace + " namespace. It can be however referenced by pods in all namespaces")
+ }
+ return admission.Allowed("")
+}
+
+func (h *ContainerPatchValidator) Supports(req admission.Request) bool {
+ gvk := mesh_k8s.GroupVersion.WithKind("ContainerPatch")
+ return req.Kind.Kind == gvk.Kind && req.Kind.Version == gvk.Version && req.Kind.Group == gvk.Group
+}
diff --git a/pkg/plugins/runtime/k8s/webhooks/policy_namespace_validator.go b/pkg/plugins/runtime/k8s/webhooks/policy_namespace_validator.go
new file mode 100644
index 0000000..4b71734
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/webhooks/policy_namespace_validator.go
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 webhooks
+
+import (
+ "context"
+ "fmt"
+ core_model "github.com/apache/dubbo-kubernetes/pkg/core/resources/model"
+ "github.com/apache/dubbo-kubernetes/pkg/core/resources/registry"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+type PolicyNamespaceValidator struct {
+ Decoder *admission.Decoder
+ SystemNamespace string
+}
+
+func (p *PolicyNamespaceValidator) InjectDecoder(decoder *admission.Decoder) {
+ p.Decoder = decoder
+}
+
+func (p *PolicyNamespaceValidator) Handle(ctx context.Context, request admission.Request) admission.Response {
+ if request.Namespace != p.SystemNamespace {
+ return admission.Denied(fmt.Sprintf("policy can only be created in the system namespace:%s", p.SystemNamespace))
+ }
+ return admission.Allowed("")
+}
+
+func (p *PolicyNamespaceValidator) Supports(request admission.Request) bool {
+ desc, err := registry.Global().DescriptorFor(core_model.ResourceType(request.Kind.Kind))
+ if err != nil {
+ return false
+ }
+ return desc.IsPluginOriginated
+}
diff --git a/pkg/plugins/runtime/k8s/webhooks/service_validator.go b/pkg/plugins/runtime/k8s/webhooks/service_validator.go
new file mode 100644
index 0000000..b71d24a
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/webhooks/service_validator.go
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 webhooks
+
+import (
+ "context"
+ "fmt"
+ core_mesh "github.com/apache/dubbo-kubernetes/pkg/core/resources/apis/mesh"
+ "github.com/apache/dubbo-kubernetes/pkg/core/validators"
+ kube_core "k8s.io/api/core/v1"
+ "net/http"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// ServiceValidator validates Dubbo-specific annotations on Services.
+type ServiceValidator struct {
+ Decoder *admission.Decoder
+}
+
+// Handle admits a Service only if Kuma-specific annotations have proper values.
+func (v *ServiceValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
+ svc := &kube_core.Service{}
+
+ err := v.Decoder.Decode(req, svc)
+ if err != nil {
+ return admission.Errored(http.StatusBadRequest, err)
+ }
+
+ if err := v.validate(svc); err != nil {
+ if verr, ok := err.(*validators.ValidationError); ok {
+ return convertValidationErrorOf(*verr, svc, svc)
+ }
+ return admission.Denied(err.Error())
+ }
+
+ return admission.Allowed("")
+}
+
+func (v *ServiceValidator) validate(svc *kube_core.Service) error {
+ verr := &validators.ValidationError{}
+ for _, svcPort := range svc.Spec.Ports {
+ protocolAnnotation := fmt.Sprintf("%d.service.kuma.io/protocol", svcPort.Port)
+ protocolAnnotationValue, exists := svc.Annotations[protocolAnnotation]
+ if exists && core_mesh.ParseProtocol(protocolAnnotationValue) == core_mesh.ProtocolUnknown {
+ verr.AddViolationAt(validators.RootedAt("metadata").Field("annotations").Key(protocolAnnotation),
+ fmt.Sprintf("value %q is not valid. %s", protocolAnnotationValue, core_mesh.AllowedValuesHint(core_mesh.SupportedProtocols.Strings()...)))
+ }
+ }
+ return verr.OrNil()
+}
diff --git a/pkg/plugins/runtime/k8s/webhooks/zone_validator.go b/pkg/plugins/runtime/k8s/webhooks/zone_validator.go
new file mode 100644
index 0000000..16d4b03
--- /dev/null
+++ b/pkg/plugins/runtime/k8s/webhooks/zone_validator.go
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 webhooks
+
+import (
+ "context"
+ "github.com/apache/dubbo-kubernetes/pkg/core/managers/apis/zone"
+ k8s_common "github.com/apache/dubbo-kubernetes/pkg/plugins/common/k8s"
+ mesh_k8s "github.com/apache/dubbo-kubernetes/pkg/plugins/resources/k8s/native/api/v1alpha1"
+ v1 "k8s.io/api/admission/v1"
+ "net/http"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+func NewZoneValidatorWebhook(validator zone.Validator, unsafeDelete bool) k8s_common.AdmissionValidator {
+ return &ZoneValidator{
+ validator: validator,
+ unsafeDelete: unsafeDelete,
+ }
+}
+
+type ZoneValidator struct {
+ validator zone.Validator
+ unsafeDelete bool
+}
+
+func (z *ZoneValidator) InjectDecoder(_ *admission.Decoder) {
+}
+
+func (z *ZoneValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
+ switch req.Operation {
+ case v1.Delete:
+ return z.ValidateDelete(ctx, req)
+ }
+ return admission.Allowed("")
+}
+
+func (z *ZoneValidator) ValidateDelete(ctx context.Context, req admission.Request) admission.Response {
+ if !z.unsafeDelete {
+ if err := z.validator.ValidateDelete(ctx, req.Name); err != nil {
+ return admission.Errored(http.StatusBadRequest, err)
+ }
+ }
+ return admission.Allowed("")
+}
+
+func (z *ZoneValidator) Supports(req admission.Request) bool {
+ gvk := mesh_k8s.GroupVersion.WithKind("Zone")
+ return req.Kind.Kind == gvk.Kind && req.Kind.Version == gvk.Version && req.Kind.Group == gvk.Group
+}
diff --git a/test/app/consumer/deployment.yaml b/test/app/consumer/deployment.yaml
new file mode 100644
index 0000000..23409e7
--- /dev/null
+++ b/test/app/consumer/deployment.yaml
@@ -0,0 +1,55 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: dubbo-samples-apiserver-consumer
+ namespace: dubbo-system
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: dubbo-samples-apiserver-consumer
+ template:
+ metadata:
+ labels:
+ app: dubbo-samples-apiserver-consumer
+ spec:
+ serviceAccountName: dubbo-sa
+ containers:
+ - name: server
+ image: apache/dubbo-demo:dubbo-samples-apiserver-consumer_0.0.1
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 20880
+ livenessProbe:
+ httpGet:
+ path: /live
+ port: 22222
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /ready
+ port: 22222
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ startupProbe:
+ httpGet:
+ path: /startup
+ port: 22222
+ failureThreshold: 30
+ periodSeconds: 10
\ No newline at end of file
diff --git a/test/app/consumer/service.yaml b/test/app/consumer/service.yaml
new file mode 100644
index 0000000..d918e65
--- /dev/null
+++ b/test/app/consumer/service.yaml
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: dubbo-samples-apiserver-consumer
+ namespace: dubbo-system
+spec:
+ clusterIP: None
+ selector:
+ app: dubbo-samples-apiserver-consumer
+ ports:
+ - protocol: TCP
+ port: 20880
+ targetPort: 20880
\ No newline at end of file
diff --git a/test/app/provider/deployment.yaml b/test/app/provider/deployment.yaml
new file mode 100644
index 0000000..d67ed5e
--- /dev/null
+++ b/test/app/provider/deployment.yaml
@@ -0,0 +1,55 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: dubbo-samples-apiserver-provider
+ namespace: dubbo-system
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: dubbo-samples-apiserver-provider
+ template:
+ metadata:
+ labels:
+ app: dubbo-samples-apiserver-provider
+ spec:
+ serviceAccountName: dubbo-sa
+ containers:
+ - name: server
+ image: apache/dubbo-demo:dubbo-samples-apiserver-provider_0.0.1
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 20880
+ livenessProbe:
+ httpGet:
+ path: /live
+ port: 22222
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /ready
+ port: 22222
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ startupProbe:
+ httpGet:
+ path: /startup
+ port: 22222
+ failureThreshold: 30
+ periodSeconds: 10
diff --git a/test/app/provider/service.yaml b/test/app/provider/service.yaml
new file mode 100644
index 0000000..878f347
--- /dev/null
+++ b/test/app/provider/service.yaml
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: dubbo-samples-apiserver-provider
+ namespace: dubbo-system
+spec:
+ clusterIP: None
+ selector:
+ app: dubbo-samples-apiserver-provider
+ ports:
+ - protocol: TCP
+ port: 20880
+ targetPort: 20880
\ No newline at end of file
diff --git a/test/app/provider/serviceaccount.yaml b/test/app/provider/serviceaccount.yaml
new file mode 100644
index 0000000..83ec3a9
--- /dev/null
+++ b/test/app/provider/serviceaccount.yaml
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: dubbo-system
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ namespace: dubbo-system
+ name: dubbo-role
+rules:
+ - apiGroups: [ "" ]
+ resources: [ "pods" ]
+ verbs: [ "get", "watch", "list", "update", "patch" ]
+ - apiGroups: [ "", "service.dubbo.apache.org" ]
+ resources: [ "services", "endpoints", "virtualservices", "destinationrules" ]
+ verbs: [ "get", "watch", "list" ]
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: dubbo-sa
+ namespace: dubbo-system
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: dubbo-sa-bind
+ namespace: dubbo-system
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: dubbo-role
+subjects:
+ - kind: ServiceAccount
+ name: dubbo-sa
\ No newline at end of file