You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by "robocanic (via GitHub)" <gi...@apache.org> on 2025/10/21 00:44:27 UTC

[PR] feat: support kubernetes as a backend engine [dubbo-admin]

robocanic opened a new pull request, #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340

   **Please provide a description of this PR:**
   Using client-go to do list-watch to kubernetes and transformed the pod into admin `RuntimeInstanceResourrce`, during the event processing, complete the linkage update of the `InstanceResource`
   
   **To help us figure out who should review this PR, please put an X in all the areas that this PR affects.**
   
   - [ ] Docs
   - [ ] Installation
   - [ ] User Experience
   - [ ] Dubboctl
   - [ ] Console
   - [x] Core Component
   
   
   **Please check any characteristics that apply to this pull request.**
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2448600498


##########
pkg/core/engine/subscriber/runtime_instance.go:
##########
@@ -0,0 +1,185 @@
+/*
+ * 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 subscriber
+
+import (
+	"errors"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/strutil"
+	"k8s.io/client-go/tools/cache"
+
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	"github.com/apache/dubbo-admin/pkg/core/events"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+	"github.com/apache/dubbo-admin/pkg/core/store"
+	"github.com/apache/dubbo-admin/pkg/core/store/index"
+)
+
+type RuntimeInstanceEventSubscriber struct {
+	instanceResourceStore store.ResourceStore
+	eventEmitter          events.Emitter
+}
+
+func (s *RuntimeInstanceEventSubscriber) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (s *RuntimeInstanceEventSubscriber) Name() string {
+	return "Engine-" + s.ResourceKind().ToString()
+}
+
+func (s *RuntimeInstanceEventSubscriber) ProcessEvent(event events.Event) error {
+	newObj, ok := event.NewObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && newObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.NewObj()).Name())
+	}
+	oldObj, ok := event.OldObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && oldObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.OldObj()).Name())
+	}
+	var processErr error
+	switch event.Type() {
+	case cache.Added, cache.Updated, cache.Replaced, cache.Sync:
+		if newObj == nil {
+			errStr := "process runtime instance upsert event, but new obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processUpsert(newObj)
+	case cache.Deleted:
+		if oldObj == nil {
+			errStr := "process runtime instance delete event, but old obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processDelete(oldObj)
+	}
+	eventStr := event.String()
+	if processErr == nil {
+		logger.Infof("process runtime instance event successfully, event: %s", eventStr)
+	} else {
+		logger.Errorf("process runtime instance event failed, event: %s, err: %s", eventStr, processErr.Error())
+	}
+	return processErr
+}
+
+func (s *RuntimeInstanceEventSubscriber) getRelatedInstanceResource(
+	rtInstance *meshresource.RuntimeInstanceResource) (*meshresource.InstanceResource, error) {
+	resources, err := s.instanceResourceStore.ListByIndexes(map[string]string{
+		index.ByInstanceIpIndex: rtInstance.Spec.Ip,
+	})
+	if err != nil {
+		return nil, err
+	}
+	if len(resources) == 0 {
+		return nil, nil
+	}
+	instanceResources := make([]*meshresource.InstanceResource, len(resources))
+	for i, item := range resources {
+		if res, ok := item.(*meshresource.InstanceResource); ok {
+			instanceResources[i] = res
+		} else {
+			return nil, bizerror.NewAssertionError("InstanceResource", reflect.TypeOf(item).Name())
+		}
+	}
+	return instanceResources[0], nil
+}
+
+func (s *RuntimeInstanceEventSubscriber) mergeRuntimeInstance(
+	instanceRes *meshresource.InstanceResource,
+	rtInstanceRes *meshresource.RuntimeInstanceResource) {
+	instanceRes.Name = rtInstanceRes.Name
+	instanceRes.Spec.Name = rtInstanceRes.Spec.Name
+	instanceRes.Spec.Ip = rtInstanceRes.Spec.Ip
+	instanceRes.Labels = rtInstanceRes.Labels
+	instanceRes.Spec.Image = rtInstanceRes.Spec.Image
+	instanceRes.Spec.CreateTime = rtInstanceRes.Spec.CreateTime
+	instanceRes.Spec.StartTime = rtInstanceRes.Spec.StartTime
+	instanceRes.Spec.ReadyTime = rtInstanceRes.Spec.ReadyTime
+	instanceRes.Spec.DeployState = rtInstanceRes.Spec.Phase
+	instanceRes.Spec.WorkloadType = rtInstanceRes.Spec.WorkloadType
+	instanceRes.Spec.WorkloadName = rtInstanceRes.Spec.WorkloadName
+	instanceRes.Spec.Node = rtInstanceRes.Spec.Node
+	instanceRes.Spec.Probes = rtInstanceRes.Spec.Probes
+	instanceRes.Spec.Conditions = rtInstanceRes.Spec.Conditions
+}
+
+func (s *RuntimeInstanceEventSubscriber) fromRuntimeInstance(
+	rtInstanceRes *meshresource.RuntimeInstanceResource) *meshresource.InstanceResource {
+	instanceRes := meshresource.NewInstanceResourceWithAttributes(rtInstanceRes.Name, rtInstanceRes.Mesh)
+	s.mergeRuntimeInstance(instanceRes, rtInstanceRes)
+	return instanceRes
+}
+
+// processUpsert when runtime instance added or updated, we should add/update the corresponding instance resource
+func (s *RuntimeInstanceEventSubscriber) processUpsert(rtInstanceRes *meshresource.RuntimeInstanceResource) error {
+	instanceResource, err := s.getRelatedInstanceResource(rtInstanceRes)
+	if err != nil {
+		return err
+	}
+	// If instance resource exists, the rpc instance resource exists in remote registry and has been watched by discovery.
+	// So we should merge the runtime info into it
+	if instanceResource != nil {
+		s.mergeRuntimeInstance(instanceResource, rtInstanceRes)
+		return s.instanceResourceStore.Update(instanceResource)
+	}
+	// If instance resource does not exist, we should create a new instance resource by runtime instance
+	// If the app name is empty, we cannot identify it as a dubbo app, so we skip it
+	if strutil.IsBlank(rtInstanceRes.Spec.AppName) {
+		logger.Warnf("cannot identify runtime instance %s as a dubbo app, skipped updating instance", rtInstanceRes.Name)
+		return nil
+	}
+	// Otherwise we can create a new instance resource by runtime instance
+	instanceRes := s.fromRuntimeInstance(rtInstanceRes)
+	if err = s.instanceResourceStore.Add(instanceRes); err != nil {
+		logger.Errorf("add instance resource failed, instance: %s, err: %s", instanceRes.ResourceKey(), err.Error())
+		return err
+	}
+	instanceAddEvent := events.NewResourceChangedEvent(cache.Added, nil, instanceRes)
+	s.eventEmitter.Send(instanceAddEvent)
+	logger.Debugf("runtime instance upsert trigger instance add event, event: %s", instanceAddEvent.String())
+	return nil
+}
+
+// processDelete when runtime instance deleted, we should delete the corresponding instance resource
+func (s *RuntimeInstanceEventSubscriber) processDelete(rtInstanceRes *meshresource.RuntimeInstanceResource) error {
+	instanceResource, err := s.getRelatedInstanceResource(rtInstanceRes)
+	if err != nil {
+		return err
+	}
+	if instanceResource == nil {
+		return nil
+	}
+	if err = s.instanceResourceStore.Delete(instanceResource.ResourceKey()); err != nil {
+		logger.Errorf("delete instance resource failed, instance: %s, err: %s", instanceResource.ResourceKey(), err.Error())
+		return err
+	}
+	instanceDeleteEvent := events.NewResourceChangedEvent(cache.Deleted, instanceResource, nil)
+	s.eventEmitter.Send(instanceDeleteEvent)
+	logger.Debugf("runtime instance delete trigger instance delete event, event: %s", instanceDeleteEvent.String())
+	return nil
+}
+
+func NewRuntimeInstanceEventSubscriber(instanceResourceStore store.ResourceStore) events.Subscriber {
+	return &RuntimeInstanceEventSubscriber{
+		instanceResourceStore: instanceResourceStore,

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2446466709


##########
app/dubbo-admin/dubbo-admin.yaml:
##########
@@ -39,17 +39,55 @@ console:
 store:
   type: memory
 discovery:
-  - type: nacos
-    id: nacos-44.33
-    address:
-      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
-  - type: istio
+#  - type: nacos
+#    id: nacos-44.33
+#    address:
+#      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
+  # mock discovery is only for development
+  - type: mock
 engine:
   name: k8s1.28.6
   type: kubernetes
   properties:
-    apiServerAddress: https://192.168.1.1:6443
-    kubeConfig: /etc/kubernetes/admin.conf
+    # [Kubernetes] Path to kubernetes config file, if not set, will use in cluster config
+    kubeConfigPath: /root/.kube/config
+    # [Kubernetes] Watch pods with specified labels, if not set, will watch all pods
+    # podWatchSelector: org.apache.dubbo/dubbo-apps=true
+    # [Kubernetes] Identify which Dubbo app the pod belongs to, if not set, [type = ByIP] will be used
+    # 1. ByLabels: Use the label value corresponding to the labelKey as the dubbo app name
+    # e.g.
+    #    type: ByLabel
+    #    labelKey: org.apache.dubbo/dubbo-app-name
+    # 2. ByAnnotation: Use the annotation value corresponding to the annotationKey as the dubbo app name
+    # e.g.
+    #    type: ByAnnotation
+    #    annotationKey: org.apache.dubbo/dubbo-app-name
+    # 3. ByIP(default): Use pod's IP to find if there is a same ip of an instance and use the instance's app name as the identifier,
+    # if there is no such association, the pod will not be seen as a pod of dubbo application.
+    # e.g.
+    #    type: ByIP
+#    dubboAppIdentifier:
+#      type: ByLabels

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2446455105


##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint: 0.0.0.0: %d", s.config.ServerPort)

Review Comment:
   The log message format is inconsistent. The colon after '0.0.0.0' should be removed or the format should use '%s:%d' pattern for clarity.
   ```suggestion
   	logger.Infof("starting diagnostic server, endpoint: %s:%d", "0.0.0.0", s.config.ServerPort)
   ```



##########
pkg/core/engine/subscriber/runtime_instance.go:
##########
@@ -0,0 +1,185 @@
+/*
+ * 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 subscriber
+
+import (
+	"errors"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/strutil"
+	"k8s.io/client-go/tools/cache"
+
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	"github.com/apache/dubbo-admin/pkg/core/events"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+	"github.com/apache/dubbo-admin/pkg/core/store"
+	"github.com/apache/dubbo-admin/pkg/core/store/index"
+)
+
+type RuntimeInstanceEventSubscriber struct {
+	instanceResourceStore store.ResourceStore
+	eventEmitter          events.Emitter
+}
+
+func (s *RuntimeInstanceEventSubscriber) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (s *RuntimeInstanceEventSubscriber) Name() string {
+	return "Engine-" + s.ResourceKind().ToString()
+}
+
+func (s *RuntimeInstanceEventSubscriber) ProcessEvent(event events.Event) error {
+	newObj, ok := event.NewObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && newObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.NewObj()).Name())
+	}
+	oldObj, ok := event.OldObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && oldObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.OldObj()).Name())
+	}
+	var processErr error
+	switch event.Type() {
+	case cache.Added, cache.Updated, cache.Replaced, cache.Sync:
+		if newObj == nil {
+			errStr := "process runtime instance upsert event, but new obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processUpsert(newObj)
+	case cache.Deleted:
+		if oldObj == nil {
+			errStr := "process runtime instance delete event, but old obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processDelete(oldObj)
+	}
+	eventStr := event.String()
+	if processErr != nil {

Review Comment:
   The condition on line 76 is inverted. Success logging should occur when `processErr == nil`, and error logging when `processErr != nil`.
   ```suggestion
   	if processErr == nil {
   ```



##########
pkg/core/engine/subscriber/runtime_instance.go:
##########
@@ -0,0 +1,185 @@
+/*
+ * 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 subscriber
+
+import (
+	"errors"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/strutil"
+	"k8s.io/client-go/tools/cache"
+
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	"github.com/apache/dubbo-admin/pkg/core/events"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+	"github.com/apache/dubbo-admin/pkg/core/store"
+	"github.com/apache/dubbo-admin/pkg/core/store/index"
+)
+
+type RuntimeInstanceEventSubscriber struct {
+	instanceResourceStore store.ResourceStore
+	eventEmitter          events.Emitter
+}
+
+func (s *RuntimeInstanceEventSubscriber) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (s *RuntimeInstanceEventSubscriber) Name() string {
+	return "Engine-" + s.ResourceKind().ToString()
+}
+
+func (s *RuntimeInstanceEventSubscriber) ProcessEvent(event events.Event) error {
+	newObj, ok := event.NewObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && newObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.NewObj()).Name())
+	}
+	oldObj, ok := event.OldObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && oldObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.OldObj()).Name())
+	}
+	var processErr error
+	switch event.Type() {
+	case cache.Added, cache.Updated, cache.Replaced, cache.Sync:
+		if newObj == nil {
+			errStr := "process runtime instance upsert event, but new obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processUpsert(newObj)
+	case cache.Deleted:
+		if oldObj == nil {
+			errStr := "process runtime instance delete event, but old obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processDelete(oldObj)
+	}
+	eventStr := event.String()
+	if processErr != nil {
+		logger.Infof("process runtime instance event successfully, event: %s", eventStr)
+	} else {
+		logger.Errorf("process runtime instance event failed, event: %s, err: %s", eventStr, processErr.Error())
+	}
+	return processErr
+}
+
+func (s *RuntimeInstanceEventSubscriber) getRelatedInstanceResource(
+	rtInstance *meshresource.RuntimeInstanceResource) (*meshresource.InstanceResource, error) {
+	resources, err := s.instanceResourceStore.ListByIndexes(map[string]string{
+		index.ByInstanceIpIndex: rtInstance.Spec.Ip,
+	})
+	if err != nil {
+		return nil, err
+	}
+	if len(resources) == 0 {
+		return nil, nil
+	}
+	instanceResources := make([]*meshresource.InstanceResource, len(resources))
+	for i, item := range resources {
+		if res, ok := item.(*meshresource.InstanceResource); ok {
+			instanceResources[i] = res
+		} else {
+			return nil, bizerror.NewAssertionError("InstanceResource", reflect.TypeOf(item).Name())
+		}
+	}
+	return instanceResources[0], nil
+}
+
+func (s *RuntimeInstanceEventSubscriber) mergeRuntimeInstance(
+	instanceRes *meshresource.InstanceResource,
+	rtInstanceRes *meshresource.RuntimeInstanceResource) {
+	instanceRes.Name = rtInstanceRes.Name
+	instanceRes.Spec.Name = rtInstanceRes.Spec.Name
+	instanceRes.Spec.Ip = rtInstanceRes.Spec.Ip
+	instanceRes.Labels = rtInstanceRes.Labels
+	instanceRes.Spec.Image = rtInstanceRes.Spec.Image
+	instanceRes.Spec.CreateTime = rtInstanceRes.Spec.CreateTime
+	instanceRes.Spec.StartTime = rtInstanceRes.Spec.StartTime
+	instanceRes.Spec.ReadyTime = rtInstanceRes.Spec.ReadyTime
+	instanceRes.Spec.DeployState = rtInstanceRes.Spec.Phase
+	instanceRes.Spec.WorkloadType = rtInstanceRes.Spec.WorkloadType
+	instanceRes.Spec.WorkloadName = rtInstanceRes.Spec.WorkloadName
+	instanceRes.Spec.Node = rtInstanceRes.Spec.Node
+	instanceRes.Spec.Probes = rtInstanceRes.Spec.Probes
+	instanceRes.Spec.Conditions = rtInstanceRes.Spec.Conditions
+}
+
+func (s *RuntimeInstanceEventSubscriber) fromRuntimeInstance(
+	rtInstanceRes *meshresource.RuntimeInstanceResource) *meshresource.InstanceResource {
+	instanceRes := meshresource.NewInstanceResourceWithAttributes(rtInstanceRes.Mesh, rtInstanceRes.Name)

Review Comment:
   Arguments appear to be reversed. Based on the function signature, the order should be `name, mesh`, not `mesh, name`.
   ```suggestion
   	instanceRes := meshresource.NewInstanceResourceWithAttributes(rtInstanceRes.Name, rtInstanceRes.Mesh)
   ```



##########
app/dubbo-admin/dubbo-admin.yaml:
##########
@@ -39,17 +39,55 @@ console:
 store:
   type: memory
 discovery:
-  - type: nacos
-    id: nacos-44.33
-    address:
-      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
-  - type: istio
+#  - type: nacos
+#    id: nacos-44.33
+#    address:
+#      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
+  # mock discovery is only for development
+  - type: mock
 engine:
   name: k8s1.28.6
   type: kubernetes
   properties:
-    apiServerAddress: https://192.168.1.1:6443
-    kubeConfig: /etc/kubernetes/admin.conf
+    # [Kubernetes] Path to kubernetes config file, if not set, will use in cluster config
+    kubeConfigPath: /root/.kube/config
+    # [Kubernetes] Watch pods with specified labels, if not set, will watch all pods
+    # podWatchSelector: org.apache.dubbo/dubbo-apps=true
+    # [Kubernetes] Identify which Dubbo app the pod belongs to, if not set, [type = ByIP] will be used
+    # 1. ByLabels: Use the label value corresponding to the labelKey as the dubbo app name
+    # e.g.
+    #    type: ByLabel
+    #    labelKey: org.apache.dubbo/dubbo-app-name
+    # 2. ByAnnotation: Use the annotation value corresponding to the annotationKey as the dubbo app name
+    # e.g.
+    #    type: ByAnnotation
+    #    annotationKey: org.apache.dubbo/dubbo-app-name
+    # 3. ByIP(default): Use pod's IP to find if there is a same ip of an instance and use the instance's app name as the identifier,
+    # if there is no such association, the pod will not be seen as a pod of dubbo application.
+    # e.g.
+    #    type: ByIP
+#    dubboAppIdentifier:
+#      type: ByLabels

Review Comment:
   Inconsistency in documentation: line 62 mentions 'ByLabel' but line 72 uses 'ByLabels'. The identifier type should be consistent with the code implementation.
   ```suggestion
   #      type: ByLabel
   ```



##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint: 0.0.0.0: %d", s.config.ServerPort)
 	errChan := make(chan error)
 	go func() {
 		defer close(errChan)
 		var err error
 		err = httpServer.ListenAndServe()
 		if err != nil {
-			switch err {
-			case http.ErrServerClosed:
-				diagnosticsServerLog.Info("shutting down server")
+			switch {
+			case errors.Is(err, http.ErrServerClosed):
+				logger.Errorf("diagnotics http server closed, err: %s", err)
 			default:
-				diagnosticsServerLog.Error(err, "could not start HTTP Server")
+				logger.Error("could not start diagnotics http Server, unknown err: %s", err)
 				errChan <- err
 			}
 			return
 		}
-		diagnosticsServerLog.Info("terminated normally")
+		logger.Info("terminated normally")
 	}()
 
 	select {
 	case <-stop:
-		diagnosticsServerLog.Info("stopping")
+		logger.Info("received stop signal, stopping diagnotics server ...")

Review Comment:
   Corrected spelling of 'diagnotics' to 'diagnostics'.
   ```suggestion
   		logger.Info("received stop signal, stopping diagnostics server ...")
   ```



##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint: 0.0.0.0: %d", s.config.ServerPort)
 	errChan := make(chan error)
 	go func() {
 		defer close(errChan)
 		var err error
 		err = httpServer.ListenAndServe()
 		if err != nil {
-			switch err {
-			case http.ErrServerClosed:
-				diagnosticsServerLog.Info("shutting down server")
+			switch {
+			case errors.Is(err, http.ErrServerClosed):
+				logger.Errorf("diagnotics http server closed, err: %s", err)
 			default:
-				diagnosticsServerLog.Error(err, "could not start HTTP Server")
+				logger.Error("could not start diagnotics http Server, unknown err: %s", err)

Review Comment:
   Corrected spelling of 'diagnotics' to 'diagnostics'.



##########
pkg/engine/kubernetes/engine.go:
##########
@@ -0,0 +1,230 @@
+/*
+ * 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 kubernetes
+
+import (
+	"fmt"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/slice"
+	"github.com/duke-git/lancet/v2/strutil"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/fields"
+	k8sruntime "k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/watch"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/cache"
+
+	meshproto "github.com/apache/dubbo-admin/api/mesh/v1alpha1"
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	enginecfg "github.com/apache/dubbo-admin/pkg/config/engine"
+	"github.com/apache/dubbo-admin/pkg/core/consts"
+	"github.com/apache/dubbo-admin/pkg/core/controller"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+)
+
+type PodListerWatcher struct {
+	cfg *enginecfg.Config
+	lw  cache.ListerWatcher
+}
+
+var _ controller.ResourceListerWatcher = &PodListerWatcher{}
+
+func NewPodListWatcher(clientset *kubernetes.Clientset, cfg *enginecfg.Config) (*PodListerWatcher, error) {
+	var selector fields.Selector
+	s := cfg.Properties.PodWatchSelector
+	if strutil.IsBlank(s) {
+		selector = fields.Everything()
+	}
+	selector, err := fields.ParseSelector(s)
+	if err != nil {
+		return nil, fmt.Errorf("parse selector %s failed: %v", s, err)
+	}
+	lw := cache.NewListWatchFromClient(
+		clientset.CoreV1().RESTClient(),
+		"pods",
+		metav1.NamespaceAll,
+		selector,
+	)
+	return &PodListerWatcher{
+		cfg: cfg,
+		lw:  lw,
+	}, nil
+}
+
+func (p *PodListerWatcher) List(options metav1.ListOptions) (k8sruntime.Object, error) {
+	return p.lw.List(options)
+}
+
+func (p *PodListerWatcher) Watch(options metav1.ListOptions) (watch.Interface, error) {
+	return p.lw.Watch(options)
+}
+
+func (p *PodListerWatcher) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (p *PodListerWatcher) TransformFunc() cache.TransformFunc {
+	return func(obj interface{}) (interface{}, error) {
+		pod, ok := obj.(*v1.Pod)
+		if !ok {
+			objType := reflect.TypeOf(obj).Name()
+			logger.Errorf("cannot transform %s to Pod", objType)
+			return nil, bizerror.NewAssertionError("Pod", objType)
+		}
+		mainContainer := p.getMainContainer(pod)
+		appName := p.getDubboAppName(pod)
+		var startTime string
+		if pod.Status.StartTime != nil {
+			startTime = pod.Status.StartTime.Format(consts.TimeFormatStr)
+		}
+		createTime := pod.CreationTimestamp.Format(consts.TimeFormatStr)
+		readyTime := ""
+		slice.ForEach(pod.Status.Conditions, func(_ int, c v1.PodCondition) {
+			if c.Type == v1.PodReady && c.Status == v1.ConditionTrue {
+				readyTime = c.LastTransitionTime.Format(consts.TimeFormatStr)
+			}
+		})
+		phase := string(pod.Status.Phase)
+		if pod.DeletionTimestamp != nil {
+			phase = meshproto.InstanceTerminating
+		}
+		var workloadName string
+		var workloadType string
+		if len(pod.GetOwnerReferences()) > 0 {
+			workloadName = pod.GetOwnerReferences()[0].Name
+			workloadType = pod.GetOwnerReferences()[0].Kind
+		}
+		conditions := slice.Map(pod.Status.Conditions, func(_ int, c v1.PodCondition) *meshproto.Condition {
+			return &meshproto.Condition{
+				Type:               string(c.Type),
+				Status:             string(c.Status),
+				LastTransitionTime: c.LastTransitionTime.Format(consts.TimeFormatStr),
+				Reason:             c.Reason,
+				Message:            c.Message,
+			}
+		})
+		var image string
+		probes := make([]*meshproto.Probe, 0)
+		if mainContainer != nil {
+			image = mainContainer.Image
+			if mainContainer.LivenessProbe != nil {
+				port := p.getProbePort(mainContainer.LivenessProbe)
+				probes = append(probes, &meshproto.Probe{
+					Type: meshproto.LivenessProbe,
+					Port: port,
+				})
+			}
+			if mainContainer.ReadinessProbe != nil {
+				port := p.getProbePort(mainContainer.ReadinessProbe)
+				probes = append(probes, &meshproto.Probe{
+					Type: meshproto.ReadinessProbe,
+					Port: port,
+				})
+			}
+			if mainContainer.StartupProbe != nil {
+				port := p.getProbePort(mainContainer.StartupProbe)
+				probes = append(probes, &meshproto.Probe{
+					Type: meshproto.StartupProbe,
+					Port: port,
+				})
+			}
+		}
+		res := meshresource.NewRuntimeInstanceResourceWithAttributes(pod.Name, "default")
+		res.Spec = &meshproto.RuntimeInstance{
+			Name:         pod.Name,
+			Ip:           pod.Status.PodIP,
+			Image:        image,
+			AppName:      appName,
+			CreateTime:   createTime,
+			StartTime:    startTime,
+			ReadyTime:    readyTime,
+			Phase:        phase,
+			WorkloadName: workloadName,
+			WorkloadType: workloadType,
+			Node:         pod.Spec.NodeName,
+			Probes:       probes,
+			Conditions:   conditions,
+		}
+		return res, nil
+	}
+}
+
+func (p *PodListerWatcher) getMainContainer(pod *v1.Pod) *v1.Container {
+	containers := pod.Spec.Containers
+	strategy := p.cfg.Properties.GetOrDefaultMainContainerChooseStrategy()
+	switch strategy.Type {
+	case enginecfg.ChooseByLast:
+		return &containers[len(containers)-1]
+	case enginecfg.ChooseByIndex:
+		return &containers[strategy.Index]
+	case enginecfg.ChooseByName:
+		c, ok := slice.FindBy[v1.Container](containers, func(_ int, c v1.Container) bool {
+			return c.Name == strategy.Name
+		})
+		if !ok {
+			logger.Warnf("pod %s has no container named %s, cannot retrieve the correct main container",
+				pod.Name, strategy.Name)
+			return nil
+		}
+		return &c
+	case enginecfg.ChooseByAnnotation:
+		value, exists := pod.Annotations[strategy.AnnotationKey]
+		if !exists {
+			logger.Warnf("pod %s has no annotaion %s, cannot retrieve the correct main container",

Review Comment:
   Corrected spelling of 'annotaion' to 'annotation'.
   ```suggestion
   			logger.Warnf("pod %s has no annotation %s, cannot retrieve the correct main container",
   ```



##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint: 0.0.0.0: %d", s.config.ServerPort)
 	errChan := make(chan error)
 	go func() {
 		defer close(errChan)
 		var err error
 		err = httpServer.ListenAndServe()
 		if err != nil {
-			switch err {
-			case http.ErrServerClosed:
-				diagnosticsServerLog.Info("shutting down server")
+			switch {
+			case errors.Is(err, http.ErrServerClosed):
+				logger.Errorf("diagnotics http server closed, err: %s", err)

Review Comment:
   Corrected spelling of 'diagnotics' to 'diagnostics'.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2446485675


##########
pkg/engine/kubernetes/engine.go:
##########
@@ -0,0 +1,230 @@
+/*
+ * 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 kubernetes
+
+import (
+	"fmt"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/slice"
+	"github.com/duke-git/lancet/v2/strutil"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/fields"
+	k8sruntime "k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/watch"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/cache"
+
+	meshproto "github.com/apache/dubbo-admin/api/mesh/v1alpha1"
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	enginecfg "github.com/apache/dubbo-admin/pkg/config/engine"
+	"github.com/apache/dubbo-admin/pkg/core/consts"
+	"github.com/apache/dubbo-admin/pkg/core/controller"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+)
+
+type PodListerWatcher struct {
+	cfg *enginecfg.Config
+	lw  cache.ListerWatcher
+}
+
+var _ controller.ResourceListerWatcher = &PodListerWatcher{}
+
+func NewPodListWatcher(clientset *kubernetes.Clientset, cfg *enginecfg.Config) (*PodListerWatcher, error) {
+	var selector fields.Selector
+	s := cfg.Properties.PodWatchSelector
+	if strutil.IsBlank(s) {
+		selector = fields.Everything()
+	}
+	selector, err := fields.ParseSelector(s)
+	if err != nil {
+		return nil, fmt.Errorf("parse selector %s failed: %v", s, err)
+	}

Review Comment:
   Variable `selector` is declared twice: first initialized on line 55 when `s` is blank, then reassigned on line 57. If `s` is blank, line 57 will overwrite the `fields.Everything()` value with the result of parsing an empty string, which may not be the intended behavior. Remove the assignment on line 55 or use a conditional to skip parsing when `s` is blank.
   ```suggestion
   	} else {
   		var err error
   		selector, err = fields.ParseSelector(s)
   		if err != nil {
   			return nil, fmt.Errorf("parse selector %s failed: %v", s, err)
   		}
   	}
   ```



##########
pkg/core/runtime/runtime.go:
##########
@@ -115,13 +115,18 @@ func (rt *runtime) Add(components ...Component) {
 func (rt *runtime) Start(stop <-chan struct{}) error {
 	components := maputil.Values(rt.components)
 	slice.SortBy(components, func(a, b Component) bool {
-		return a.Order() < b.Order()
+		return a.Order() > b.Order()
 	})
 	for _, com := range components {
-		err := com.Start(rt, stop)
-		if err != nil {
-			return err
-		}
+		go func() {
+			err := com.Start(rt, stop)
+			if err != nil {
+				panic("component " + com.Type() + " running failed with error: " + err.Error())
+			}
+		}()

Review Comment:
   Starting each component in a separate goroutine without synchronization means errors won't be returned to the caller, and a panic in one component's goroutine won't be caught by recover in the parent. Consider using an error group (e.g., `errgroup.Group`) to properly propagate errors and coordinate shutdown.



##########
pkg/core/controller/informer.go:
##########
@@ -91,13 +102,11 @@ type informer struct {
 	transform cache.TransformFunc
 }
 
-func NewInformerWithOptions(lw cache.ListerWatcher, emitter events.Emitter, store store.ResourceStore,
-	exampleObject runtime.Object, options Options) Informer {
+func NewInformerWithOptions(lw cache.ListerWatcher, emitter events.Emitter, store store.ResourceStore, options Options) Informer {
 	return &informer{
 		indexer:           store,
 		listerWatcher:     lw,
 		emitter:           emitter,

Review Comment:
   The `objectType` field is no longer set in the constructor (previously set on line 109 before removal), but it may still be referenced elsewhere in the `informer` struct. Verify that removing this initialization doesn't break functionality or remove the field from the struct definition.
   ```suggestion
   func NewInformerWithOptions(lw cache.ListerWatcher, emitter events.Emitter, store store.ResourceStore, objectType runtime.Object, options Options) Informer {
   	return &informer{
   		indexer:           store,
   		listerWatcher:     lw,
   		emitter:           emitter,
   		objectType:        objectType,
   ```



##########
pkg/core/engine/subscriber/runtime_instance.go:
##########
@@ -0,0 +1,185 @@
+/*
+ * 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 subscriber
+
+import (
+	"errors"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/strutil"
+	"k8s.io/client-go/tools/cache"
+
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	"github.com/apache/dubbo-admin/pkg/core/events"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+	"github.com/apache/dubbo-admin/pkg/core/store"
+	"github.com/apache/dubbo-admin/pkg/core/store/index"
+)
+
+type RuntimeInstanceEventSubscriber struct {
+	instanceResourceStore store.ResourceStore
+	eventEmitter          events.Emitter
+}
+
+func (s *RuntimeInstanceEventSubscriber) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (s *RuntimeInstanceEventSubscriber) Name() string {
+	return "Engine-" + s.ResourceKind().ToString()
+}
+
+func (s *RuntimeInstanceEventSubscriber) ProcessEvent(event events.Event) error {
+	newObj, ok := event.NewObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && newObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.NewObj()).Name())
+	}
+	oldObj, ok := event.OldObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && oldObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.OldObj()).Name())
+	}
+	var processErr error
+	switch event.Type() {
+	case cache.Added, cache.Updated, cache.Replaced, cache.Sync:
+		if newObj == nil {
+			errStr := "process runtime instance upsert event, but new obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processUpsert(newObj)
+	case cache.Deleted:
+		if oldObj == nil {
+			errStr := "process runtime instance delete event, but old obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processDelete(oldObj)
+	}
+	eventStr := event.String()
+	if processErr == nil {
+		logger.Infof("process runtime instance event successfully, event: %s", eventStr)
+	} else {
+		logger.Errorf("process runtime instance event failed, event: %s, err: %s", eventStr, processErr.Error())
+	}
+	return processErr
+}
+
+func (s *RuntimeInstanceEventSubscriber) getRelatedInstanceResource(
+	rtInstance *meshresource.RuntimeInstanceResource) (*meshresource.InstanceResource, error) {
+	resources, err := s.instanceResourceStore.ListByIndexes(map[string]string{
+		index.ByInstanceIpIndex: rtInstance.Spec.Ip,
+	})
+	if err != nil {
+		return nil, err
+	}
+	if len(resources) == 0 {
+		return nil, nil
+	}
+	instanceResources := make([]*meshresource.InstanceResource, len(resources))
+	for i, item := range resources {
+		if res, ok := item.(*meshresource.InstanceResource); ok {
+			instanceResources[i] = res
+		} else {
+			return nil, bizerror.NewAssertionError("InstanceResource", reflect.TypeOf(item).Name())
+		}
+	}
+	return instanceResources[0], nil
+}
+
+func (s *RuntimeInstanceEventSubscriber) mergeRuntimeInstance(
+	instanceRes *meshresource.InstanceResource,
+	rtInstanceRes *meshresource.RuntimeInstanceResource) {
+	instanceRes.Name = rtInstanceRes.Name
+	instanceRes.Spec.Name = rtInstanceRes.Spec.Name
+	instanceRes.Spec.Ip = rtInstanceRes.Spec.Ip
+	instanceRes.Labels = rtInstanceRes.Labels
+	instanceRes.Spec.Image = rtInstanceRes.Spec.Image
+	instanceRes.Spec.CreateTime = rtInstanceRes.Spec.CreateTime
+	instanceRes.Spec.StartTime = rtInstanceRes.Spec.StartTime
+	instanceRes.Spec.ReadyTime = rtInstanceRes.Spec.ReadyTime
+	instanceRes.Spec.DeployState = rtInstanceRes.Spec.Phase
+	instanceRes.Spec.WorkloadType = rtInstanceRes.Spec.WorkloadType
+	instanceRes.Spec.WorkloadName = rtInstanceRes.Spec.WorkloadName
+	instanceRes.Spec.Node = rtInstanceRes.Spec.Node
+	instanceRes.Spec.Probes = rtInstanceRes.Spec.Probes
+	instanceRes.Spec.Conditions = rtInstanceRes.Spec.Conditions
+}
+
+func (s *RuntimeInstanceEventSubscriber) fromRuntimeInstance(
+	rtInstanceRes *meshresource.RuntimeInstanceResource) *meshresource.InstanceResource {
+	instanceRes := meshresource.NewInstanceResourceWithAttributes(rtInstanceRes.Name, rtInstanceRes.Mesh)
+	s.mergeRuntimeInstance(instanceRes, rtInstanceRes)
+	return instanceRes
+}
+
+// processUpsert when runtime instance added or updated, we should add/update the corresponding instance resource
+func (s *RuntimeInstanceEventSubscriber) processUpsert(rtInstanceRes *meshresource.RuntimeInstanceResource) error {
+	instanceResource, err := s.getRelatedInstanceResource(rtInstanceRes)
+	if err != nil {
+		return err
+	}
+	// If instance resource exists, the rpc instance resource exists in remote registry and has been watched by discovery.
+	// So we should merge the runtime info into it
+	if instanceResource != nil {
+		s.mergeRuntimeInstance(instanceResource, rtInstanceRes)
+		return s.instanceResourceStore.Update(instanceResource)
+	}
+	// If instance resource does not exist, we should create a new instance resource by runtime instance
+	// If the app name is empty, we cannot identify it as a dubbo app, so we skip it
+	if strutil.IsBlank(rtInstanceRes.Spec.AppName) {
+		logger.Warnf("cannot identify runtime instance %s as a dubbo app, skipped updating instance", rtInstanceRes.Name)
+		return nil
+	}
+	// Otherwise we can create a new instance resource by runtime instance
+	instanceRes := s.fromRuntimeInstance(rtInstanceRes)
+	if err = s.instanceResourceStore.Add(instanceRes); err != nil {
+		logger.Errorf("add instance resource failed, instance: %s, err: %s", instanceRes.ResourceKey(), err.Error())
+		return err
+	}
+	instanceAddEvent := events.NewResourceChangedEvent(cache.Added, nil, instanceRes)
+	s.eventEmitter.Send(instanceAddEvent)
+	logger.Debugf("runtime instance upsert trigger instance add event, event: %s", instanceAddEvent.String())
+	return nil
+}
+
+// processDelete when runtime instance deleted, we should delete the corresponding instance resource
+func (s *RuntimeInstanceEventSubscriber) processDelete(rtInstanceRes *meshresource.RuntimeInstanceResource) error {
+	instanceResource, err := s.getRelatedInstanceResource(rtInstanceRes)
+	if err != nil {
+		return err
+	}
+	if instanceResource == nil {
+		return nil
+	}
+	if err = s.instanceResourceStore.Delete(instanceResource.ResourceKey()); err != nil {
+		logger.Errorf("delete instance resource failed, instance: %s, err: %s", instanceResource.ResourceKey(), err.Error())
+		return err
+	}
+	instanceDeleteEvent := events.NewResourceChangedEvent(cache.Deleted, instanceResource, nil)
+	s.eventEmitter.Send(instanceDeleteEvent)
+	logger.Debugf("runtime instance delete trigger instance delete event, event: %s", instanceDeleteEvent.String())
+	return nil
+}
+
+func NewRuntimeInstanceEventSubscriber(instanceResourceStore store.ResourceStore) events.Subscriber {
+	return &RuntimeInstanceEventSubscriber{
+		instanceResourceStore: instanceResourceStore,

Review Comment:
   The `eventEmitter` field is not initialized in the constructor but is used in `processUpsert` (line 157) and `processDelete` (line 176). This will cause a nil pointer dereference. Add an `eventEmitter` parameter to the constructor.
   ```suggestion
   func NewRuntimeInstanceEventSubscriber(instanceResourceStore store.ResourceStore, eventEmitter events.Emitter) events.Subscriber {
   	return &RuntimeInstanceEventSubscriber{
   		instanceResourceStore: instanceResourceStore,
   		eventEmitter:          eventEmitter,
   ```



##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint is 0.0.0.0: %d", s.config.ServerPort)
 	errChan := make(chan error)
 	go func() {
 		defer close(errChan)
 		var err error
 		err = httpServer.ListenAndServe()
 		if err != nil {
-			switch err {
-			case http.ErrServerClosed:
-				diagnosticsServerLog.Info("shutting down server")
+			switch {
+			case errors.Is(err, http.ErrServerClosed):
+				logger.Errorf("diagnostics http server closed, err: %s", err)

Review Comment:
   The log message says 'diagnostics http server closed' with an error level, but `http.ErrServerClosed` is the expected normal shutdown error. This should be logged at Info level with message 'shutting down server' (matching the original behavior) rather than as an error.
   ```suggestion
   				logger.Info("shutting down diagnostics server")
   ```



##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint is 0.0.0.0: %d", s.config.ServerPort)
 	errChan := make(chan error)
 	go func() {
 		defer close(errChan)
 		var err error
 		err = httpServer.ListenAndServe()
 		if err != nil {
-			switch err {
-			case http.ErrServerClosed:
-				diagnosticsServerLog.Info("shutting down server")
+			switch {
+			case errors.Is(err, http.ErrServerClosed):
+				logger.Errorf("diagnostics http server closed, err: %s", err)
 			default:
-				diagnosticsServerLog.Error(err, "could not start HTTP Server")
+				logger.Error("could not start diagnostics http Server, unknown err: %s", err)

Review Comment:
   Corrected capitalization of 'Server' to 'server'.
   ```suggestion
   				logger.Error("could not start diagnostics http server, unknown err: %s", err)
   ```



##########
app/dubbo-admin/dubbo-admin.yaml:
##########
@@ -39,17 +39,55 @@ console:
 store:
   type: memory
 discovery:
-  - type: nacos
-    id: nacos-44.33
-    address:
-      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
-  - type: istio
+#  - type: nacos
+#    id: nacos-44.33
+#    address:
+#      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
+  # mock discovery is only for development
+  - type: mock
 engine:
   name: k8s1.28.6
   type: kubernetes
   properties:
-    apiServerAddress: https://192.168.1.1:6443
-    kubeConfig: /etc/kubernetes/admin.conf
+    # [Kubernetes] Path to kubernetes config file, if not set, will use in cluster config
+    kubeConfigPath: /root/.kube/config
+    # [Kubernetes] Watch pods with specified labels, if not set, will watch all pods
+    # podWatchSelector: org.apache.dubbo/dubbo-apps=true
+    # [Kubernetes] Identify which Dubbo app the pod belongs to, if not set, [type = ByIP] will be used
+    # 1. ByLabels: Use the label value corresponding to the labelKey as the dubbo app name
+    # e.g.
+    #    type: ByLabel
+    #    labelKey: org.apache.dubbo/dubbo-app-name
+    # 2. ByAnnotation: Use the annotation value corresponding to the annotationKey as the dubbo app name
+    # e.g.
+    #    type: ByAnnotation
+    #    annotationKey: org.apache.dubbo/dubbo-app-name
+    # 3. ByIP(default): Use pod's IP to find if there is a same ip of an instance and use the instance's app name as the identifier,
+    # if there is no such association, the pod will not be seen as a pod of dubbo application.
+    # e.g.
+    #    type: ByIP
+#    dubboAppIdentifier:
+#      type: ByLabel
+#      labelKey: org.apache.dubbo/dubbo-app-name
+    # [Kubernetes] Strategy of choosing the main container, if not set, [type = ByIndex] and [index = 0] will be used
+    # 1. ByLast: choose the last container as the main container
+    # e.g.
+    #    type: ByLast
+    # 2. ByIndex(default): choose the container at the specified index location as the main container
+    # e.g.
+    #    type: ByIndex
+    #    index: 0
+    # 3. ByName: choose the container with the specified name
+    # e.g.
+    #    type: ByName
+    #    name: main
+    # 4. chooseByAnnotation: choose the container with the annotation key, specified annotation value will be used as the container name

Review Comment:
   Corrected spelling of 'chooseByAnnotation' to 'ByAnnotation' to match the constant name.
   ```suggestion
       # 4. ByAnnotation: choose the container with the annotation key, specified annotation value will be used as the container name
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2448661620


##########
pkg/core/runtime/runtime.go:
##########
@@ -115,13 +116,26 @@ func (rt *runtime) Add(components ...Component) {
 func (rt *runtime) Start(stop <-chan struct{}) error {
 	components := maputil.Values(rt.components)
 	slice.SortBy(components, func(a, b Component) bool {
-		return a.Order() < b.Order()
+		return a.Order() > b.Order()
 	})
 	for _, com := range components {
-		err := com.Start(rt, stop)
-		if err != nil {
-			return err
-		}
+		go func() {
+			err := com.Start(rt, stop)
+			if err != nil {
+				// if a core component failed to start, panic
+				if slice.Contain(CoreComponentTypes, com.Type()) {
+					panic("core component " + com.Type() + " running failed with error: " + err.Error())
+				} else {
+					logger.Errorf("component %s running failed with error: %s", com.Type(), err.Error())
+				}
+			} else {
+				logger.Infof("component %s started successfully", com.Type())
+			}

Review Comment:
   Starting all components concurrently without waiting for initialization dependencies could lead to race conditions. Components may depend on earlier components being fully initialized (e.g., EventBus must be ready before Engine). Consider adding synchronization or ordering guarantees for dependent components.



##########
pkg/core/engine/component.go:
##########
@@ -69,40 +107,45 @@ func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
 		return err
 	}
 	for _, lw := range lwList {
-		eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
-		if err != nil {
-			return err
-		}
-		emitter, ok := eventBusComponent.(events.Emitter)
-		if !ok {
-			return fmt.Errorf("type assertion failed, event bus component in runtime is not an Emitter")
-		}
-		storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
-		if err != nil {
-			return err
-		}
-		resourceStore, ok := storeComponent.(store.ResourceStore)
-		if !ok {
-			return fmt.Errorf("type assertion failed, resource store component in runtime is not a ResourceStore")
-		}
 		rk := lw.ResourceKind()
-		newFunc, err := coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+		rs, err := e.storeRouter.ResourceKindRoute(rk)
 		if err != nil {
-			return err
+			return fmt.Errorf("can not find store for resource kind %s, %w", rk, err)
+		}
+		informer := controller.NewInformerWithOptions(lw, emitter, rs, controller.Options{ResyncPeriod: 0})
+		if lw.TransformFunc() != nil {
+			err = informer.SetTransform(lw.TransformFunc())
+			if err != nil {
+				return fmt.Errorf("can not set transform for informer of resource kind %s, %w", rk, err)

Review Comment:
   Corrected 'can not' to 'cannot' for consistency.



##########
pkg/core/engine/component.go:
##########
@@ -41,25 +45,59 @@ type Component interface {
 var _ Component = &engineComponent{}
 
 type engineComponent struct {
-	name      string
-	informers []controller.Informer
+	name                string
+	storeRouter         store.Router
+	informers           []controller.Informer
+	subscriptionManager events.SubscriptionManager
+	subscribers         []events.Subscriber
 }
 
 func newEngineComponent() Component {
 	return &engineComponent{
-		informers: make([]controller.Informer, 0),
+		informers:   make([]controller.Informer, 0),
+		subscribers: make([]events.Subscriber, 0),
 	}
 }
-func (b *engineComponent) Type() runtime.ComponentType {
+func (e *engineComponent) Type() runtime.ComponentType {
 	return runtime.ResourceEngine
 }
 
-func (b *engineComponent) Order() int {
-	return math.MaxInt
+func (e *engineComponent) Order() int {
+	return math.MaxInt - 3
 }
 
-func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
+func (e *engineComponent) Init(ctx runtime.BuilderContext) error {
 	cfg := ctx.Config().Engine
+	e.name = cfg.Name
+	eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
+	if err != nil {
+		return fmt.Errorf("can not retrieve event bus from runtime in engine %s, %w", cfg.Name, err)
+	}
+	eventBus, ok := eventBusComponent.(events.EventBus)
+	if !ok {
+		return bizerror.NewAssertionError("EventBus", reflect.TypeOf(eventBusComponent).Name())
+	}
+	e.subscriptionManager = eventBus
+	storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
+	if err != nil {
+		return fmt.Errorf("can not retrieve store from runtime in engine %s, %w", e.name, err)

Review Comment:
   Corrected 'can not' to 'cannot' for consistency.
   ```suggestion
   		return fmt.Errorf("cannot retrieve store from runtime in engine %s, %w", e.name, err)
   ```



##########
pkg/core/engine/component.go:
##########
@@ -69,40 +107,45 @@ func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
 		return err
 	}
 	for _, lw := range lwList {
-		eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
-		if err != nil {
-			return err
-		}
-		emitter, ok := eventBusComponent.(events.Emitter)
-		if !ok {
-			return fmt.Errorf("type assertion failed, event bus component in runtime is not an Emitter")
-		}
-		storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
-		if err != nil {
-			return err
-		}
-		resourceStore, ok := storeComponent.(store.ResourceStore)
-		if !ok {
-			return fmt.Errorf("type assertion failed, resource store component in runtime is not a ResourceStore")
-		}
 		rk := lw.ResourceKind()
-		newFunc, err := coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+		rs, err := e.storeRouter.ResourceKindRoute(rk)
 		if err != nil {
-			return err
+			return fmt.Errorf("can not find store for resource kind %s, %w", rk, err)
+		}
+		informer := controller.NewInformerWithOptions(lw, emitter, rs, controller.Options{ResyncPeriod: 0})
+		if lw.TransformFunc() != nil {
+			err = informer.SetTransform(lw.TransformFunc())
+			if err != nil {
+				return fmt.Errorf("can not set transform for informer of resource kind %s, %w", rk, err)
+			}
 		}
-		informer := controller.NewInformerWithOptions(lw, emitter, resourceStore,
-			newFunc(), controller.Options{ResyncPeriod: 0})
-		b.informers = append(b.informers, informer)
+		e.informers = append(e.informers, informer)
+		logger.Infof("resource engine %s has added informer for resource kind %s", e.name, rk)
+	}
+	return nil
+}
+
+func (e *engineComponent) initSubscribers(eventbus events.EventBus) error {
+	rs, err := e.storeRouter.ResourceKindRoute(meshresource.InstanceKind)
+	if err != nil {
+		return fmt.Errorf("can not find store for resource kind %s, %w", meshresource.RuntimeInstanceKind, err)

Review Comment:
   Corrected 'can not' to 'cannot' for consistency.
   ```suggestion
   		return fmt.Errorf("cannot find store for resource kind %s, %w", meshresource.RuntimeInstanceKind, err)
   ```



##########
pkg/core/engine/component.go:
##########
@@ -41,25 +45,59 @@ type Component interface {
 var _ Component = &engineComponent{}
 
 type engineComponent struct {
-	name      string
-	informers []controller.Informer
+	name                string
+	storeRouter         store.Router
+	informers           []controller.Informer
+	subscriptionManager events.SubscriptionManager
+	subscribers         []events.Subscriber
 }
 
 func newEngineComponent() Component {
 	return &engineComponent{
-		informers: make([]controller.Informer, 0),
+		informers:   make([]controller.Informer, 0),
+		subscribers: make([]events.Subscriber, 0),
 	}
 }
-func (b *engineComponent) Type() runtime.ComponentType {
+func (e *engineComponent) Type() runtime.ComponentType {
 	return runtime.ResourceEngine
 }
 
-func (b *engineComponent) Order() int {
-	return math.MaxInt
+func (e *engineComponent) Order() int {
+	return math.MaxInt - 3
 }
 
-func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
+func (e *engineComponent) Init(ctx runtime.BuilderContext) error {
 	cfg := ctx.Config().Engine
+	e.name = cfg.Name
+	eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
+	if err != nil {
+		return fmt.Errorf("can not retrieve event bus from runtime in engine %s, %w", cfg.Name, err)

Review Comment:
   Corrected 'can not' to 'cannot' for consistency.



##########
pkg/core/discovery/component.go:
##########
@@ -110,21 +113,26 @@ func (d *discoveryComponent) newInformers(cfg *discovery.Config, ctx runtime.Bui
 	if err != nil {
 		return nil, err
 	}
-	emitter := eventBusComponent.(events.Emitter)
+	emitter, ok := eventBusComponent.(events.Emitter)
+	if !ok {
+		return nil, bizerror.NewAssertionError("Emitter", reflect.TypeOf(eventBusComponent).Name())
+	}
 	storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("can not retrieve store from runtime in engine %s, %w", cfg.Name, err)

Review Comment:
   Corrected 'can not' to 'cannot' for consistency.
   ```suggestion
   		return nil, fmt.Errorf("cannot retrieve store from runtime in engine %s, %w", cfg.Name, err)
   ```



##########
pkg/core/engine/component.go:
##########
@@ -69,40 +107,45 @@ func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
 		return err
 	}
 	for _, lw := range lwList {
-		eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
-		if err != nil {
-			return err
-		}
-		emitter, ok := eventBusComponent.(events.Emitter)
-		if !ok {
-			return fmt.Errorf("type assertion failed, event bus component in runtime is not an Emitter")
-		}
-		storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
-		if err != nil {
-			return err
-		}
-		resourceStore, ok := storeComponent.(store.ResourceStore)
-		if !ok {
-			return fmt.Errorf("type assertion failed, resource store component in runtime is not a ResourceStore")
-		}
 		rk := lw.ResourceKind()
-		newFunc, err := coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+		rs, err := e.storeRouter.ResourceKindRoute(rk)
 		if err != nil {
-			return err
+			return fmt.Errorf("can not find store for resource kind %s, %w", rk, err)

Review Comment:
   Corrected 'can not' to 'cannot' for consistency.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2450146618


##########
pkg/core/discovery/component.go:
##########
@@ -110,21 +113,26 @@ func (d *discoveryComponent) newInformers(cfg *discovery.Config, ctx runtime.Bui
 	if err != nil {
 		return nil, err
 	}
-	emitter := eventBusComponent.(events.Emitter)
+	emitter, ok := eventBusComponent.(events.Emitter)
+	if !ok {
+		return nil, bizerror.NewAssertionError("Emitter", reflect.TypeOf(eventBusComponent).Name())
+	}
 	storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("can not retrieve store from runtime in engine %s, %w", cfg.Name, err)

Review Comment:
   ignored



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "sonarqubecloud[bot] (via GitHub)" <gi...@apache.org>.
sonarqubecloud[bot] commented on PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#issuecomment-3424254760

   ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340) **Quality Gate passed**  
   Issues  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=ACCEPTED)
   
   Measures  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_coverage&view=list)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_duplicated_lines_density&view=list)  
     
   [See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2484234660


##########
api/mesh/v1alpha1/rpc_instance_metadata.proto:
##########
@@ -6,7 +6,7 @@ option go_package = "github.com/apache/dubbo-admin/api/mesh/v1alpha1";
 
 import "api/mesh/options.proto";
 
-message RPCInstanceMetaData {
+message RpcInstanceMetadata {

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "AlexStocks (via GitHub)" <gi...@apache.org>.
AlexStocks merged PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2450146018


##########
pkg/core/engine/component.go:
##########
@@ -69,40 +107,45 @@ func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
 		return err
 	}
 	for _, lw := range lwList {
-		eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
-		if err != nil {
-			return err
-		}
-		emitter, ok := eventBusComponent.(events.Emitter)
-		if !ok {
-			return fmt.Errorf("type assertion failed, event bus component in runtime is not an Emitter")
-		}
-		storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
-		if err != nil {
-			return err
-		}
-		resourceStore, ok := storeComponent.(store.ResourceStore)
-		if !ok {
-			return fmt.Errorf("type assertion failed, resource store component in runtime is not a ResourceStore")
-		}
 		rk := lw.ResourceKind()
-		newFunc, err := coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+		rs, err := e.storeRouter.ResourceKindRoute(rk)
 		if err != nil {
-			return err
+			return fmt.Errorf("can not find store for resource kind %s, %w", rk, err)
+		}
+		informer := controller.NewInformerWithOptions(lw, emitter, rs, controller.Options{ResyncPeriod: 0})
+		if lw.TransformFunc() != nil {
+			err = informer.SetTransform(lw.TransformFunc())
+			if err != nil {
+				return fmt.Errorf("can not set transform for informer of resource kind %s, %w", rk, err)

Review Comment:
   ignored



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "sonarqubecloud[bot] (via GitHub)" <gi...@apache.org>.
sonarqubecloud[bot] commented on PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#issuecomment-3477476203

   ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340) **Quality Gate passed**  
   Issues  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=ACCEPTED)
   
   Measures  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_coverage&view=list)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_duplicated_lines_density&view=list)  
     
   [See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2446460384


##########
pkg/engine/kubernetes/engine.go:
##########
@@ -0,0 +1,230 @@
+/*
+ * 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 kubernetes
+
+import (
+	"fmt"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/slice"
+	"github.com/duke-git/lancet/v2/strutil"
+	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/fields"
+	k8sruntime "k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/watch"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/cache"
+
+	meshproto "github.com/apache/dubbo-admin/api/mesh/v1alpha1"
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	enginecfg "github.com/apache/dubbo-admin/pkg/config/engine"
+	"github.com/apache/dubbo-admin/pkg/core/consts"
+	"github.com/apache/dubbo-admin/pkg/core/controller"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+)
+
+type PodListerWatcher struct {
+	cfg *enginecfg.Config
+	lw  cache.ListerWatcher
+}
+
+var _ controller.ResourceListerWatcher = &PodListerWatcher{}
+
+func NewPodListWatcher(clientset *kubernetes.Clientset, cfg *enginecfg.Config) (*PodListerWatcher, error) {
+	var selector fields.Selector
+	s := cfg.Properties.PodWatchSelector
+	if strutil.IsBlank(s) {
+		selector = fields.Everything()
+	}
+	selector, err := fields.ParseSelector(s)
+	if err != nil {
+		return nil, fmt.Errorf("parse selector %s failed: %v", s, err)
+	}
+	lw := cache.NewListWatchFromClient(
+		clientset.CoreV1().RESTClient(),
+		"pods",
+		metav1.NamespaceAll,
+		selector,
+	)
+	return &PodListerWatcher{
+		cfg: cfg,
+		lw:  lw,
+	}, nil
+}
+
+func (p *PodListerWatcher) List(options metav1.ListOptions) (k8sruntime.Object, error) {
+	return p.lw.List(options)
+}
+
+func (p *PodListerWatcher) Watch(options metav1.ListOptions) (watch.Interface, error) {
+	return p.lw.Watch(options)
+}
+
+func (p *PodListerWatcher) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (p *PodListerWatcher) TransformFunc() cache.TransformFunc {
+	return func(obj interface{}) (interface{}, error) {
+		pod, ok := obj.(*v1.Pod)
+		if !ok {
+			objType := reflect.TypeOf(obj).Name()
+			logger.Errorf("cannot transform %s to Pod", objType)
+			return nil, bizerror.NewAssertionError("Pod", objType)
+		}
+		mainContainer := p.getMainContainer(pod)
+		appName := p.getDubboAppName(pod)
+		var startTime string
+		if pod.Status.StartTime != nil {
+			startTime = pod.Status.StartTime.Format(consts.TimeFormatStr)
+		}
+		createTime := pod.CreationTimestamp.Format(consts.TimeFormatStr)
+		readyTime := ""
+		slice.ForEach(pod.Status.Conditions, func(_ int, c v1.PodCondition) {
+			if c.Type == v1.PodReady && c.Status == v1.ConditionTrue {
+				readyTime = c.LastTransitionTime.Format(consts.TimeFormatStr)
+			}
+		})
+		phase := string(pod.Status.Phase)
+		if pod.DeletionTimestamp != nil {
+			phase = meshproto.InstanceTerminating
+		}
+		var workloadName string
+		var workloadType string
+		if len(pod.GetOwnerReferences()) > 0 {
+			workloadName = pod.GetOwnerReferences()[0].Name
+			workloadType = pod.GetOwnerReferences()[0].Kind
+		}
+		conditions := slice.Map(pod.Status.Conditions, func(_ int, c v1.PodCondition) *meshproto.Condition {
+			return &meshproto.Condition{
+				Type:               string(c.Type),
+				Status:             string(c.Status),
+				LastTransitionTime: c.LastTransitionTime.Format(consts.TimeFormatStr),
+				Reason:             c.Reason,
+				Message:            c.Message,
+			}
+		})
+		var image string
+		probes := make([]*meshproto.Probe, 0)
+		if mainContainer != nil {
+			image = mainContainer.Image
+			if mainContainer.LivenessProbe != nil {
+				port := p.getProbePort(mainContainer.LivenessProbe)
+				probes = append(probes, &meshproto.Probe{
+					Type: meshproto.LivenessProbe,
+					Port: port,
+				})
+			}
+			if mainContainer.ReadinessProbe != nil {
+				port := p.getProbePort(mainContainer.ReadinessProbe)
+				probes = append(probes, &meshproto.Probe{
+					Type: meshproto.ReadinessProbe,
+					Port: port,
+				})
+			}
+			if mainContainer.StartupProbe != nil {
+				port := p.getProbePort(mainContainer.StartupProbe)
+				probes = append(probes, &meshproto.Probe{
+					Type: meshproto.StartupProbe,
+					Port: port,
+				})
+			}
+		}
+		res := meshresource.NewRuntimeInstanceResourceWithAttributes(pod.Name, "default")
+		res.Spec = &meshproto.RuntimeInstance{
+			Name:         pod.Name,
+			Ip:           pod.Status.PodIP,
+			Image:        image,
+			AppName:      appName,
+			CreateTime:   createTime,
+			StartTime:    startTime,
+			ReadyTime:    readyTime,
+			Phase:        phase,
+			WorkloadName: workloadName,
+			WorkloadType: workloadType,
+			Node:         pod.Spec.NodeName,
+			Probes:       probes,
+			Conditions:   conditions,
+		}
+		return res, nil
+	}
+}
+
+func (p *PodListerWatcher) getMainContainer(pod *v1.Pod) *v1.Container {
+	containers := pod.Spec.Containers
+	strategy := p.cfg.Properties.GetOrDefaultMainContainerChooseStrategy()
+	switch strategy.Type {
+	case enginecfg.ChooseByLast:
+		return &containers[len(containers)-1]
+	case enginecfg.ChooseByIndex:
+		return &containers[strategy.Index]
+	case enginecfg.ChooseByName:
+		c, ok := slice.FindBy[v1.Container](containers, func(_ int, c v1.Container) bool {
+			return c.Name == strategy.Name
+		})
+		if !ok {
+			logger.Warnf("pod %s has no container named %s, cannot retrieve the correct main container",
+				pod.Name, strategy.Name)
+			return nil
+		}
+		return &c
+	case enginecfg.ChooseByAnnotation:
+		value, exists := pod.Annotations[strategy.AnnotationKey]
+		if !exists {
+			logger.Warnf("pod %s has no annotaion %s, cannot retrieve the correct main container",

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2446463374


##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint: 0.0.0.0: %d", s.config.ServerPort)

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "sonarqubecloud[bot] (via GitHub)" <gi...@apache.org>.
sonarqubecloud[bot] commented on PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#issuecomment-3427099751

   ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340) **Quality Gate passed**  
   Issues  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=ACCEPTED)
   
   Measures  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_coverage&view=list)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_duplicated_lines_density&view=list)  
     
   [See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2484229449


##########
pkg/core/resource/apis/mesh/v1alpha1/affinityroute_types.go:
##########
@@ -106,6 +108,15 @@ func (r *AffinityRouteResource) DeepCopyObject() k8sruntime.Object {
 	return out
 }
 
+func (r *AffinityRouteResource) String() string {
+	jsonStr, err := json.Marshal(r)
+	if err != nil {
+		logger.Errorf("failed to encode AffinityRouteResource: %s to json, err: %s", r.ResourceKey(), err)

Review Comment:
   这是打错误日志,日志是用%s,如果是返回一个err,则用fmt.ErrorOf("%w", err)来包装一下



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2448643658


##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint is 0.0.0.0: %d", s.config.ServerPort)
 	errChan := make(chan error)
 	go func() {
 		defer close(errChan)
 		var err error
 		err = httpServer.ListenAndServe()
 		if err != nil {
-			switch err {
-			case http.ErrServerClosed:
-				diagnosticsServerLog.Info("shutting down server")
+			switch {
+			case errors.Is(err, http.ErrServerClosed):
+				logger.Errorf("diagnostics http server closed, err: %s", err)

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "sonarqubecloud[bot] (via GitHub)" <gi...@apache.org>.
sonarqubecloud[bot] commented on PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#issuecomment-3424275994

   ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340) **Quality Gate passed**  
   Issues  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=ACCEPTED)
   
   Measures  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_coverage&view=list)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_duplicated_lines_density&view=list)  
     
   [See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "sonarqubecloud[bot] (via GitHub)" <gi...@apache.org>.
sonarqubecloud[bot] commented on PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#issuecomment-3424292228

   ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340) **Quality Gate passed**  
   Issues  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=ACCEPTED)
   
   Measures  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=apache_dubbo-admin&pullRequest=1340&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_coverage&view=list)  
   ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=apache_dubbo-admin&pullRequest=1340&metric=new_duplicated_lines_density&view=list)  
     
   [See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=apache_dubbo-admin&pullRequest=1340)
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "AlexStocks (via GitHub)" <gi...@apache.org>.
AlexStocks commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2483070983


##########
pkg/core/resource/apis/mesh/v1alpha1/affinityroute_types.go:
##########
@@ -106,6 +108,15 @@ func (r *AffinityRouteResource) DeepCopyObject() k8sruntime.Object {
 	return out
 }
 
+func (r *AffinityRouteResource) String() string {
+	jsonStr, err := json.Marshal(r)
+	if err != nil {
+		logger.Errorf("failed to encode AffinityRouteResource: %s to json, err: %s", r.ResourceKey(), err)

Review Comment:
   error 输出一般这样写: err: %w,其他地方也改下吧



##########
api/mesh/v1alpha1/rpc_instance_metadata.proto:
##########
@@ -6,7 +6,7 @@ option go_package = "github.com/apache/dubbo-admin/api/mesh/v1alpha1";
 
 import "api/mesh/options.proto";
 
-message RPCInstanceMetaData {
+message RpcInstanceMetadata {

Review Comment:
   <img width="1550" height="522" alt="Image" src="https://github.com/user-attachments/assets/3b220bde-41bd-47d4-a209-b5c054469b71" />



##########
pkg/core/resource/apis/mesh/v1alpha1/application_types.go:
##########
@@ -106,6 +108,15 @@ func (r *ApplicationResource) DeepCopyObject() k8sruntime.Object {
 	return out
 }
 
+func (r *ApplicationResource) String() string {
+	jsonStr, err := json.Marshal(r)
+	if err != nil {
+		logger.Errorf("failed to encode ApplicationResource: %s to json, err: %s", r.ResourceKey(), err)

Review Comment:
   error 输出一般这样写: err: %w



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2448645677


##########
app/dubbo-admin/dubbo-admin.yaml:
##########
@@ -39,17 +39,55 @@ console:
 store:
   type: memory
 discovery:
-  - type: nacos
-    id: nacos-44.33
-    address:
-      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
-      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
-  - type: istio
+#  - type: nacos
+#    id: nacos-44.33
+#    address:
+#      registry: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      configCenter: nacos://47.76.94.134:8848?username=nacos&password=nacos
+#      metadataReport: nacos://47.76.94.134:8848?username=nacos&password=nacos
+  # mock discovery is only for development
+  - type: mock
 engine:
   name: k8s1.28.6
   type: kubernetes
   properties:
-    apiServerAddress: https://192.168.1.1:6443
-    kubeConfig: /etc/kubernetes/admin.conf
+    # [Kubernetes] Path to kubernetes config file, if not set, will use in cluster config
+    kubeConfigPath: /root/.kube/config
+    # [Kubernetes] Watch pods with specified labels, if not set, will watch all pods
+    # podWatchSelector: org.apache.dubbo/dubbo-apps=true
+    # [Kubernetes] Identify which Dubbo app the pod belongs to, if not set, [type = ByIP] will be used
+    # 1. ByLabels: Use the label value corresponding to the labelKey as the dubbo app name
+    # e.g.
+    #    type: ByLabel
+    #    labelKey: org.apache.dubbo/dubbo-app-name
+    # 2. ByAnnotation: Use the annotation value corresponding to the annotationKey as the dubbo app name
+    # e.g.
+    #    type: ByAnnotation
+    #    annotationKey: org.apache.dubbo/dubbo-app-name
+    # 3. ByIP(default): Use pod's IP to find if there is a same ip of an instance and use the instance's app name as the identifier,
+    # if there is no such association, the pod will not be seen as a pod of dubbo application.
+    # e.g.
+    #    type: ByIP
+#    dubboAppIdentifier:
+#      type: ByLabel
+#      labelKey: org.apache.dubbo/dubbo-app-name
+    # [Kubernetes] Strategy of choosing the main container, if not set, [type = ByIndex] and [index = 0] will be used
+    # 1. ByLast: choose the last container as the main container
+    # e.g.
+    #    type: ByLast
+    # 2. ByIndex(default): choose the container at the specified index location as the main container
+    # e.g.
+    #    type: ByIndex
+    #    index: 0
+    # 3. ByName: choose the container with the specified name
+    # e.g.
+    #    type: ByName
+    #    name: main
+    # 4. chooseByAnnotation: choose the container with the annotation key, specified annotation value will be used as the container name

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2448644751


##########
pkg/diagnostics/server.go:
##########
@@ -79,31 +76,30 @@ func (s *diagnosticsServer) Start(_ runtime.Runtime, stop <-chan struct{}) error
 		Addr:              fmt.Sprintf(":%d", s.config.ServerPort),
 		Handler:           mux,
 		ReadHeaderTimeout: time.Second,
-		ErrorLog:          adapter.ToStd(diagnosticsServerLog),
 	}
 
-	diagnosticsServerLog.Info("starting diagnostic server", "interface", "0.0.0.0", "port", s.config.ServerPort)
+	logger.Infof("starting diagnostic server, endpoint is 0.0.0.0: %d", s.config.ServerPort)
 	errChan := make(chan error)
 	go func() {
 		defer close(errChan)
 		var err error
 		err = httpServer.ListenAndServe()
 		if err != nil {
-			switch err {
-			case http.ErrServerClosed:
-				diagnosticsServerLog.Info("shutting down server")
+			switch {
+			case errors.Is(err, http.ErrServerClosed):
+				logger.Errorf("diagnostics http server closed, err: %s", err)
 			default:
-				diagnosticsServerLog.Error(err, "could not start HTTP Server")
+				logger.Error("could not start diagnostics http Server, unknown err: %s", err)

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2450147152


##########
pkg/core/engine/component.go:
##########
@@ -69,40 +107,45 @@ func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
 		return err
 	}
 	for _, lw := range lwList {
-		eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
-		if err != nil {
-			return err
-		}
-		emitter, ok := eventBusComponent.(events.Emitter)
-		if !ok {
-			return fmt.Errorf("type assertion failed, event bus component in runtime is not an Emitter")
-		}
-		storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
-		if err != nil {
-			return err
-		}
-		resourceStore, ok := storeComponent.(store.ResourceStore)
-		if !ok {
-			return fmt.Errorf("type assertion failed, resource store component in runtime is not a ResourceStore")
-		}
 		rk := lw.ResourceKind()
-		newFunc, err := coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+		rs, err := e.storeRouter.ResourceKindRoute(rk)
 		if err != nil {
-			return err
+			return fmt.Errorf("can not find store for resource kind %s, %w", rk, err)

Review Comment:
   ignored



##########
pkg/core/engine/component.go:
##########
@@ -69,40 +107,45 @@ func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
 		return err
 	}
 	for _, lw := range lwList {
-		eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
-		if err != nil {
-			return err
-		}
-		emitter, ok := eventBusComponent.(events.Emitter)
-		if !ok {
-			return fmt.Errorf("type assertion failed, event bus component in runtime is not an Emitter")
-		}
-		storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
-		if err != nil {
-			return err
-		}
-		resourceStore, ok := storeComponent.(store.ResourceStore)
-		if !ok {
-			return fmt.Errorf("type assertion failed, resource store component in runtime is not a ResourceStore")
-		}
 		rk := lw.ResourceKind()
-		newFunc, err := coremodel.ResourceSchemaRegistry().NewResourceFunc(rk)
+		rs, err := e.storeRouter.ResourceKindRoute(rk)
 		if err != nil {
-			return err
+			return fmt.Errorf("can not find store for resource kind %s, %w", rk, err)
+		}
+		informer := controller.NewInformerWithOptions(lw, emitter, rs, controller.Options{ResyncPeriod: 0})
+		if lw.TransformFunc() != nil {
+			err = informer.SetTransform(lw.TransformFunc())
+			if err != nil {
+				return fmt.Errorf("can not set transform for informer of resource kind %s, %w", rk, err)
+			}
 		}
-		informer := controller.NewInformerWithOptions(lw, emitter, resourceStore,
-			newFunc(), controller.Options{ResyncPeriod: 0})
-		b.informers = append(b.informers, informer)
+		e.informers = append(e.informers, informer)
+		logger.Infof("resource engine %s has added informer for resource kind %s", e.name, rk)
+	}
+	return nil
+}
+
+func (e *engineComponent) initSubscribers(eventbus events.EventBus) error {
+	rs, err := e.storeRouter.ResourceKindRoute(meshresource.InstanceKind)
+	if err != nil {
+		return fmt.Errorf("can not find store for resource kind %s, %w", meshresource.RuntimeInstanceKind, err)

Review Comment:
   ignored



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2448605484


##########
pkg/core/controller/informer.go:
##########
@@ -91,13 +102,11 @@ type informer struct {
 	transform cache.TransformFunc
 }
 
-func NewInformerWithOptions(lw cache.ListerWatcher, emitter events.Emitter, store store.ResourceStore,
-	exampleObject runtime.Object, options Options) Informer {
+func NewInformerWithOptions(lw cache.ListerWatcher, emitter events.Emitter, store store.ResourceStore, options Options) Informer {
 	return &informer{
 		indexer:           store,
 		listerWatcher:     lw,
 		emitter:           emitter,

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2446462406


##########
pkg/core/engine/subscriber/runtime_instance.go:
##########
@@ -0,0 +1,185 @@
+/*
+ * 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 subscriber
+
+import (
+	"errors"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/strutil"
+	"k8s.io/client-go/tools/cache"
+
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	"github.com/apache/dubbo-admin/pkg/core/events"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+	"github.com/apache/dubbo-admin/pkg/core/store"
+	"github.com/apache/dubbo-admin/pkg/core/store/index"
+)
+
+type RuntimeInstanceEventSubscriber struct {
+	instanceResourceStore store.ResourceStore
+	eventEmitter          events.Emitter
+}
+
+func (s *RuntimeInstanceEventSubscriber) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (s *RuntimeInstanceEventSubscriber) Name() string {
+	return "Engine-" + s.ResourceKind().ToString()
+}
+
+func (s *RuntimeInstanceEventSubscriber) ProcessEvent(event events.Event) error {
+	newObj, ok := event.NewObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && newObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.NewObj()).Name())
+	}
+	oldObj, ok := event.OldObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && oldObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.OldObj()).Name())
+	}
+	var processErr error
+	switch event.Type() {
+	case cache.Added, cache.Updated, cache.Replaced, cache.Sync:
+		if newObj == nil {
+			errStr := "process runtime instance upsert event, but new obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processUpsert(newObj)
+	case cache.Deleted:
+		if oldObj == nil {
+			errStr := "process runtime instance delete event, but old obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processDelete(oldObj)
+	}
+	eventStr := event.String()
+	if processErr != nil {
+		logger.Infof("process runtime instance event successfully, event: %s", eventStr)
+	} else {
+		logger.Errorf("process runtime instance event failed, event: %s, err: %s", eventStr, processErr.Error())
+	}
+	return processErr
+}
+
+func (s *RuntimeInstanceEventSubscriber) getRelatedInstanceResource(
+	rtInstance *meshresource.RuntimeInstanceResource) (*meshresource.InstanceResource, error) {
+	resources, err := s.instanceResourceStore.ListByIndexes(map[string]string{
+		index.ByInstanceIpIndex: rtInstance.Spec.Ip,
+	})
+	if err != nil {
+		return nil, err
+	}
+	if len(resources) == 0 {
+		return nil, nil
+	}
+	instanceResources := make([]*meshresource.InstanceResource, len(resources))
+	for i, item := range resources {
+		if res, ok := item.(*meshresource.InstanceResource); ok {
+			instanceResources[i] = res
+		} else {
+			return nil, bizerror.NewAssertionError("InstanceResource", reflect.TypeOf(item).Name())
+		}
+	}
+	return instanceResources[0], nil
+}
+
+func (s *RuntimeInstanceEventSubscriber) mergeRuntimeInstance(
+	instanceRes *meshresource.InstanceResource,
+	rtInstanceRes *meshresource.RuntimeInstanceResource) {
+	instanceRes.Name = rtInstanceRes.Name
+	instanceRes.Spec.Name = rtInstanceRes.Spec.Name
+	instanceRes.Spec.Ip = rtInstanceRes.Spec.Ip
+	instanceRes.Labels = rtInstanceRes.Labels
+	instanceRes.Spec.Image = rtInstanceRes.Spec.Image
+	instanceRes.Spec.CreateTime = rtInstanceRes.Spec.CreateTime
+	instanceRes.Spec.StartTime = rtInstanceRes.Spec.StartTime
+	instanceRes.Spec.ReadyTime = rtInstanceRes.Spec.ReadyTime
+	instanceRes.Spec.DeployState = rtInstanceRes.Spec.Phase
+	instanceRes.Spec.WorkloadType = rtInstanceRes.Spec.WorkloadType
+	instanceRes.Spec.WorkloadName = rtInstanceRes.Spec.WorkloadName
+	instanceRes.Spec.Node = rtInstanceRes.Spec.Node
+	instanceRes.Spec.Probes = rtInstanceRes.Spec.Probes
+	instanceRes.Spec.Conditions = rtInstanceRes.Spec.Conditions
+}
+
+func (s *RuntimeInstanceEventSubscriber) fromRuntimeInstance(
+	rtInstanceRes *meshresource.RuntimeInstanceResource) *meshresource.InstanceResource {
+	instanceRes := meshresource.NewInstanceResourceWithAttributes(rtInstanceRes.Mesh, rtInstanceRes.Name)

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2446461225


##########
pkg/core/engine/subscriber/runtime_instance.go:
##########
@@ -0,0 +1,185 @@
+/*
+ * 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 subscriber
+
+import (
+	"errors"
+	"reflect"
+
+	"github.com/duke-git/lancet/v2/strutil"
+	"k8s.io/client-go/tools/cache"
+
+	"github.com/apache/dubbo-admin/pkg/common/bizerror"
+	"github.com/apache/dubbo-admin/pkg/core/events"
+	"github.com/apache/dubbo-admin/pkg/core/logger"
+	meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
+	coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
+	"github.com/apache/dubbo-admin/pkg/core/store"
+	"github.com/apache/dubbo-admin/pkg/core/store/index"
+)
+
+type RuntimeInstanceEventSubscriber struct {
+	instanceResourceStore store.ResourceStore
+	eventEmitter          events.Emitter
+}
+
+func (s *RuntimeInstanceEventSubscriber) ResourceKind() coremodel.ResourceKind {
+	return meshresource.RuntimeInstanceKind
+}
+
+func (s *RuntimeInstanceEventSubscriber) Name() string {
+	return "Engine-" + s.ResourceKind().ToString()
+}
+
+func (s *RuntimeInstanceEventSubscriber) ProcessEvent(event events.Event) error {
+	newObj, ok := event.NewObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && newObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.NewObj()).Name())
+	}
+	oldObj, ok := event.OldObj().(*meshresource.RuntimeInstanceResource)
+	if !ok && oldObj != nil {
+		return bizerror.NewAssertionError(meshresource.RuntimeInstanceKind, reflect.TypeOf(event.OldObj()).Name())
+	}
+	var processErr error
+	switch event.Type() {
+	case cache.Added, cache.Updated, cache.Replaced, cache.Sync:
+		if newObj == nil {
+			errStr := "process runtime instance upsert event, but new obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processUpsert(newObj)
+	case cache.Deleted:
+		if oldObj == nil {
+			errStr := "process runtime instance delete event, but old obj is nil, skipped processing"
+			logger.Error(errStr)
+			return errors.New(errStr)
+		}
+		processErr = s.processDelete(oldObj)
+	}
+	eventStr := event.String()
+	if processErr != nil {

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2450146833


##########
pkg/core/engine/component.go:
##########
@@ -41,25 +45,59 @@ type Component interface {
 var _ Component = &engineComponent{}
 
 type engineComponent struct {
-	name      string
-	informers []controller.Informer
+	name                string
+	storeRouter         store.Router
+	informers           []controller.Informer
+	subscriptionManager events.SubscriptionManager
+	subscribers         []events.Subscriber
 }
 
 func newEngineComponent() Component {
 	return &engineComponent{
-		informers: make([]controller.Informer, 0),
+		informers:   make([]controller.Informer, 0),
+		subscribers: make([]events.Subscriber, 0),
 	}
 }
-func (b *engineComponent) Type() runtime.ComponentType {
+func (e *engineComponent) Type() runtime.ComponentType {
 	return runtime.ResourceEngine
 }
 
-func (b *engineComponent) Order() int {
-	return math.MaxInt
+func (e *engineComponent) Order() int {
+	return math.MaxInt - 3
 }
 
-func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
+func (e *engineComponent) Init(ctx runtime.BuilderContext) error {
 	cfg := ctx.Config().Engine
+	e.name = cfg.Name
+	eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
+	if err != nil {
+		return fmt.Errorf("can not retrieve event bus from runtime in engine %s, %w", cfg.Name, err)

Review Comment:
   ignored



##########
pkg/core/engine/component.go:
##########
@@ -41,25 +45,59 @@ type Component interface {
 var _ Component = &engineComponent{}
 
 type engineComponent struct {
-	name      string
-	informers []controller.Informer
+	name                string
+	storeRouter         store.Router
+	informers           []controller.Informer
+	subscriptionManager events.SubscriptionManager
+	subscribers         []events.Subscriber
 }
 
 func newEngineComponent() Component {
 	return &engineComponent{
-		informers: make([]controller.Informer, 0),
+		informers:   make([]controller.Informer, 0),
+		subscribers: make([]events.Subscriber, 0),
 	}
 }
-func (b *engineComponent) Type() runtime.ComponentType {
+func (e *engineComponent) Type() runtime.ComponentType {
 	return runtime.ResourceEngine
 }
 
-func (b *engineComponent) Order() int {
-	return math.MaxInt
+func (e *engineComponent) Order() int {
+	return math.MaxInt - 3
 }
 
-func (b *engineComponent) Init(ctx runtime.BuilderContext) error {
+func (e *engineComponent) Init(ctx runtime.BuilderContext) error {
 	cfg := ctx.Config().Engine
+	e.name = cfg.Name
+	eventBusComponent, err := ctx.GetActivatedComponent(runtime.EventBus)
+	if err != nil {
+		return fmt.Errorf("can not retrieve event bus from runtime in engine %s, %w", cfg.Name, err)
+	}
+	eventBus, ok := eventBusComponent.(events.EventBus)
+	if !ok {
+		return bizerror.NewAssertionError("EventBus", reflect.TypeOf(eventBusComponent).Name())
+	}
+	e.subscriptionManager = eventBus
+	storeComponent, err := ctx.GetActivatedComponent(runtime.ResourceStore)
+	if err != nil {
+		return fmt.Errorf("can not retrieve store from runtime in engine %s, %w", e.name, err)

Review Comment:
   ignored



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org


Re: [PR] feat: support kubernetes as a backend engine [dubbo-admin]

Posted by "robocanic (via GitHub)" <gi...@apache.org>.
robocanic commented on code in PR #1340:
URL: https://github.com/apache/dubbo-admin/pull/1340#discussion_r2450145676


##########
pkg/core/runtime/runtime.go:
##########
@@ -115,13 +116,26 @@ func (rt *runtime) Add(components ...Component) {
 func (rt *runtime) Start(stop <-chan struct{}) error {
 	components := maputil.Values(rt.components)
 	slice.SortBy(components, func(a, b Component) bool {
-		return a.Order() < b.Order()
+		return a.Order() > b.Order()
 	})
 	for _, com := range components {
-		err := com.Start(rt, stop)
-		if err != nil {
-			return err
-		}
+		go func() {
+			err := com.Start(rt, stop)
+			if err != nil {
+				// if a core component failed to start, panic
+				if slice.Contain(CoreComponentTypes, com.Type()) {
+					panic("core component " + com.Type() + " running failed with error: " + err.Error())
+				} else {
+					logger.Errorf("component %s running failed with error: %s", com.Type(), err.Error())
+				}
+			} else {
+				logger.Infof("component %s started successfully", com.Type())
+			}

Review Comment:
   already sort the components in order



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org