Skip to content

Commit 479c15d

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into feature/fix-1447
2 parents 1c8a60a + d9ebf33 commit 479c15d

21 files changed

Lines changed: 699 additions & 151 deletions

File tree

api/mesh/v1alpha1/runtime_instance_helper.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@ const (
2323
StartupProbe = "startup"
2424
)
2525

26-
const InstanceTerminating = "Terminating"
26+
const (
27+
InstanceStarting = "Starting"
28+
InstanceCrashing = "Crashing"
29+
InstanceTerminating = "Terminating"
30+
)

pkg/console/model/application.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,18 @@ func NewApplicationTabInstanceInfoReq() *ApplicationTabInstanceInfoReq {
131131
}
132132

133133
type AppInstanceInfoResp struct {
134-
AppName string `json:"appName"`
135-
CreateTime string `json:"createTime"`
136-
DeployState string `json:"deployState"`
137-
DeployClusters string `json:"deployClusters"`
138-
IP string `json:"ip"`
139-
Labels map[string]string `json:"labels"`
140-
Name string `json:"name"`
141-
RegisterCluster string `json:"registerCluster"`
142-
RegisterState string `json:"registerState"`
143-
RegisterTime string `json:"registerTime"`
144-
WorkloadName string `json:"workloadName"`
134+
AppName string `json:"appName"`
135+
CreateTime string `json:"createTime"`
136+
LifecycleState InstanceLifecycleState `json:"lifecycleState"`
137+
DeployState InstanceDeployState `json:"deployState"`
138+
DeployClusters string `json:"deployClusters"`
139+
IP string `json:"ip"`
140+
Labels map[string]string `json:"labels"`
141+
Name string `json:"name"`
142+
RegisterCluster string `json:"registerCluster"`
143+
RegisterState InstanceRegisterState `json:"registerState"`
144+
RegisterTime string `json:"registerTime"`
145+
WorkloadName string `json:"workloadName"`
145146
}
146147

147148
type ApplicationServiceReq struct {

pkg/console/model/instance.go

Lines changed: 152 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package model
2020
import (
2121
"github.com/duke-git/lancet/v2/strutil"
2222

23+
meshproto "github.com/apache/dubbo-admin/api/mesh/v1alpha1"
2324
"github.com/apache/dubbo-admin/pkg/config/app"
2425
meshresource "github.com/apache/dubbo-admin/pkg/core/resource/apis/mesh/v1alpha1"
2526
coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
@@ -54,17 +55,18 @@ func NewSearchPaginationResult() *SearchPaginationResult {
5455
}
5556

5657
type SearchInstanceResp struct {
57-
Ip string `json:"ip"`
58-
Name string `json:"name"`
59-
WorkloadName string `json:"workloadName"`
60-
AppName string `json:"appName"`
61-
DeployState string `json:"deployState"`
62-
DeployCluster string `json:"deployCluster"`
63-
RegisterState string `json:"registerState"`
64-
RegisterClusters []string `json:"registerClusters"`
65-
CreateTime string `json:"createTime"`
66-
RegisterTime string `json:"registerTime"`
67-
Labels map[string]string `json:"labels"`
58+
Ip string `json:"ip"`
59+
Name string `json:"name"`
60+
WorkloadName string `json:"workloadName"`
61+
AppName string `json:"appName"`
62+
LifecycleState InstanceLifecycleState `json:"lifecycleState"`
63+
DeployState InstanceDeployState `json:"deployState"`
64+
DeployCluster string `json:"deployCluster"`
65+
RegisterState InstanceRegisterState `json:"registerState"`
66+
RegisterClusters []string `json:"registerClusters"`
67+
CreateTime string `json:"createTime"`
68+
RegisterTime string `json:"registerTime"`
69+
Labels map[string]string `json:"labels"`
6870
}
6971

7072
func NewSearchInstanceResp() *SearchInstanceResp {
@@ -85,13 +87,10 @@ func (r *SearchInstanceResp) FromInstanceResource(instanceResource *meshresource
8587
if cfg.Engine != nil && cfg.Engine.ID == instance.SourceEngine {
8688
r.DeployCluster = cfg.Engine.Name
8789
}
88-
if r.RegisterTime != "" {
89-
r.RegisterState = "Registered"
90-
} else {
91-
r.RegisterState = "UnRegistered"
92-
}
90+
r.RegisterState = DeriveInstanceRegisterState(instance)
9391
r.Labels = instance.Tags
94-
r.DeployState = instance.DeployState
92+
r.DeployState = DeriveInstanceDeployState(instance)
93+
r.LifecycleState = DeriveInstanceLifecycleState(instance, r.DeployState, r.RegisterState)
9594
r.WorkloadName = instance.WorkloadName
9695
r.AppName = instance.AppName
9796
return r
@@ -104,23 +103,74 @@ type State struct {
104103
Value string `json:"value"`
105104
}
106105

106+
// InstanceDeployState describes the runtime deployment state reported by the platform.
107+
type InstanceDeployState string
108+
109+
const (
110+
// InstanceDeployStateUnknown indicates the deployment state cannot be derived from runtime metadata.
111+
InstanceDeployStateUnknown InstanceDeployState = "Unknown"
112+
// InstanceDeployStatePending indicates the workload has been accepted but is not running yet.
113+
InstanceDeployStatePending InstanceDeployState = "Pending"
114+
// InstanceDeployStateStarting indicates the workload is running but not ready to serve.
115+
InstanceDeployStateStarting InstanceDeployState = "Starting"
116+
// InstanceDeployStateRunning indicates the workload is running and ready.
117+
InstanceDeployStateRunning InstanceDeployState = "Running"
118+
// InstanceDeployStateTerminating indicates the workload is shutting down.
119+
InstanceDeployStateTerminating InstanceDeployState = "Terminating"
120+
// InstanceDeployStateFailed indicates the workload has failed.
121+
InstanceDeployStateFailed InstanceDeployState = "Failed"
122+
// InstanceDeployStateSucceeded indicates the workload has completed successfully and exited.
123+
InstanceDeployStateSucceeded InstanceDeployState = "Succeeded"
124+
// InstanceDeployStateCrashing indicates the workload is repeatedly crashing or restarting.
125+
InstanceDeployStateCrashing InstanceDeployState = "Crashing"
126+
)
127+
128+
// InstanceRegisterState describes whether the instance is visible to the registry.
129+
type InstanceRegisterState string
130+
131+
const (
132+
// InstanceRegisterStateRegistered indicates the instance has been registered to the registry.
133+
InstanceRegisterStateRegistered InstanceRegisterState = "Registered"
134+
// InstanceRegisterStateUnregistered indicates the instance has not registered yet or has been removed.
135+
InstanceRegisterStateUnregistered InstanceRegisterState = "UnRegistered"
136+
)
137+
138+
// InstanceLifecycleState describes the user-facing lifecycle synthesized from deploy/register signals.
139+
type InstanceLifecycleState string
140+
141+
const (
142+
// InstanceLifecycleStateStarting indicates the instance is still warming up.
143+
InstanceLifecycleStateStarting InstanceLifecycleState = "Starting"
144+
// InstanceLifecycleStateServing indicates the instance is both running and registered.
145+
InstanceLifecycleStateServing InstanceLifecycleState = "Serving"
146+
// InstanceLifecycleStateDraining indicates the instance is running but has started unregistering.
147+
InstanceLifecycleStateDraining InstanceLifecycleState = "Draining"
148+
// InstanceLifecycleStateTerminating indicates the instance is shutting down.
149+
InstanceLifecycleStateTerminating InstanceLifecycleState = "Terminating"
150+
// InstanceLifecycleStateError indicates the instance is in an unexpected or failed state.
151+
InstanceLifecycleStateError InstanceLifecycleState = "Error"
152+
// InstanceLifecycleStateUnknown indicates the lifecycle cannot be inferred from current signals.
153+
InstanceLifecycleStateUnknown InstanceLifecycleState = "Unknown"
154+
)
155+
107156
type InstanceDetailResp struct {
108-
RpcPort int64 `json:"rpcPort"`
109-
Ip string `json:"ip"`
110-
AppName string `json:"appName"`
111-
WorkloadName string `json:"workloadName"`
112-
Labels map[string]string `json:"labels"`
113-
CreateTime string `json:"createTime"`
114-
ReadyTime string `json:"readyTime"`
115-
RegisterTime string `json:"registerTime"`
116-
RegisterClusters []string `json:"registerClusters"`
117-
DeployCluster string `json:"deployCluster"`
118-
DeployState string `json:"deployState"`
119-
RegisterState string `json:"registerState"`
120-
Node string `json:"node"`
121-
Image string `json:"image"`
122-
Probes ProbeStruct `json:"probes"`
123-
Tags map[string]string `json:"tags"`
157+
RpcPort int64 `json:"rpcPort"`
158+
Ip string `json:"ip"`
159+
AppName string `json:"appName"`
160+
WorkloadName string `json:"workloadName"`
161+
Labels map[string]string `json:"labels"`
162+
CreateTime string `json:"createTime"`
163+
ReadyTime string `json:"readyTime"`
164+
RegisterTime string `json:"registerTime"`
165+
RegisterClusters []string `json:"registerClusters"`
166+
DeployCluster string `json:"deployCluster"`
167+
LifecycleState InstanceLifecycleState `json:"lifecycleState"`
168+
DeployState InstanceDeployState `json:"deployState"`
169+
RegisterState InstanceRegisterState `json:"registerState"`
170+
Node string `json:"node"`
171+
Image string `json:"image"`
172+
Probes ProbeStruct `json:"probes"`
173+
Tags map[string]string `json:"tags"`
124174
}
125175

126176
const (
@@ -158,16 +208,9 @@ func FromInstanceResource(res *meshresource.InstanceResource, cfg app.AdminConfi
158208
if cfg.Engine.ID == res.Spec.SourceEngine {
159209
r.DeployCluster = cfg.Engine.Name
160210
}
161-
if strutil.IsNotBlank(instance.DeployState) {
162-
r.DeployState = instance.DeployState
163-
} else {
164-
r.DeployState = "Unknown"
165-
}
166-
if strutil.IsBlank(r.RegisterTime) {
167-
r.RegisterState = "UnRegistered"
168-
} else {
169-
r.RegisterState = "Registered"
170-
}
211+
r.DeployState = DeriveInstanceDeployState(instance)
212+
r.RegisterState = DeriveInstanceRegisterState(instance)
213+
r.LifecycleState = DeriveInstanceLifecycleState(instance, r.DeployState, r.RegisterState)
171214
r.Node = instance.Node
172215
r.Image = instance.Image
173216
r.Probes = ProbeStruct{}
@@ -196,3 +239,69 @@ func FromInstanceResource(res *meshresource.InstanceResource, cfg app.AdminConfi
196239
}
197240
return r
198241
}
242+
243+
func DeriveInstanceDeployState(instance *meshproto.Instance) InstanceDeployState {
244+
if instance == nil || strutil.IsBlank(instance.DeployState) {
245+
return InstanceDeployStateUnknown
246+
}
247+
deployState := InstanceDeployState(instance.DeployState)
248+
switch deployState {
249+
case InstanceDeployStateRunning:
250+
if !isPodReady(instance) {
251+
return InstanceDeployStateStarting
252+
}
253+
return InstanceDeployStateRunning
254+
default:
255+
return deployState
256+
}
257+
}
258+
259+
func DeriveInstanceRegisterState(instance *meshproto.Instance) InstanceRegisterState {
260+
if instance == nil || strutil.IsBlank(instance.RegisterTime) {
261+
return InstanceRegisterStateUnregistered
262+
}
263+
return InstanceRegisterStateRegistered
264+
}
265+
266+
func DeriveInstanceLifecycleState(
267+
instance *meshproto.Instance,
268+
deployState InstanceDeployState,
269+
registerState InstanceRegisterState,
270+
) InstanceLifecycleState {
271+
switch deployState {
272+
case InstanceDeployStateCrashing, InstanceDeployStateFailed, InstanceDeployStateUnknown, InstanceDeployStateSucceeded:
273+
return InstanceLifecycleStateError
274+
case InstanceDeployStateTerminating:
275+
return InstanceLifecycleStateTerminating
276+
}
277+
278+
if registerState == InstanceRegisterStateRegistered {
279+
if deployState == InstanceDeployStateRunning {
280+
return InstanceLifecycleStateServing
281+
}
282+
return InstanceLifecycleStateError
283+
}
284+
285+
if instance != nil && deployState == InstanceDeployStateRunning && strutil.IsNotBlank(instance.UnregisterTime) {
286+
return InstanceLifecycleStateDraining
287+
}
288+
289+
switch deployState {
290+
case InstanceDeployStatePending, InstanceDeployStateStarting, InstanceDeployStateRunning:
291+
return InstanceLifecycleStateStarting
292+
default:
293+
return InstanceLifecycleStateUnknown
294+
}
295+
}
296+
297+
func isPodReady(instance *meshproto.Instance) bool {
298+
for _, condition := range instance.Conditions {
299+
if condition == nil {
300+
continue
301+
}
302+
if condition.Type == "Ready" {
303+
return condition.Status == "True"
304+
}
305+
}
306+
return false
307+
}

pkg/console/service/application.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ func buildAppInstanceInfoResp(instanceRes *meshresource.InstanceResource, cfg ap
9595
resp.Name = instance.Name
9696
resp.AppName = instance.AppName
9797
resp.CreateTime = instance.CreateTime
98-
resp.DeployState = instance.DeployState
98+
resp.DeployState = model.DeriveInstanceDeployState(instance)
99+
resp.LifecycleState = model.DeriveInstanceLifecycleState(instance, resp.DeployState, model.DeriveInstanceRegisterState(instance))
99100
if cfg.Engine.ID == instance.SourceEngine {
100101
resp.DeployClusters = cfg.Engine.Name
101102
}
@@ -104,7 +105,7 @@ func buildAppInstanceInfoResp(instanceRes *meshresource.InstanceResource, cfg ap
104105
if d := cfg.FindDiscovery(instanceRes.Mesh); d != nil {
105106
resp.RegisterCluster = d.Name
106107
}
107-
resp.RegisterState = "Registered"
108+
resp.RegisterState = model.DeriveInstanceRegisterState(instance)
108109
resp.RegisterTime = instance.RegisterTime
109110
resp.WorkloadName = instance.WorkloadName
110111
return resp

pkg/core/controller/informer.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,10 @@ func (s *informer) HandleDeltas(obj interface{}, _ bool) error {
229229
}
230230
// from oldest to newest
231231
for _, d := range deltas {
232-
var resource model.Resource
233-
var object interface{}
234-
if o, ok := d.Object.(cache.DeletedFinalStateUnknown); ok {
235-
object = o.Obj
236-
} else {
237-
object = d.Object
238-
}
239-
resource, ok := object.(model.Resource)
240-
if !ok {
241-
logger.Errorf("object from ListWatcher is not conformed to Resource, obj: %v", obj)
242-
return bizerror.NewAssertionError("Resource", reflect.TypeOf(obj).Name())
232+
resource, err := s.toResource(d.Object)
233+
if err != nil {
234+
logger.Errorf("object from ListWatcher is not conformed to Resource, obj: %v, err: %v", obj, err)
235+
return err
243236
}
244237
switch d.Type {
245238
case cache.Sync, cache.Replaced, cache.Added, cache.Updated:
@@ -257,6 +250,8 @@ func (s *informer) HandleDeltas(obj interface{}, _ bool) error {
257250
s.EmitEvent(cache.Added, nil, resource)
258251
}
259252
case cache.Deleted:
253+
logger.Infof("informer processing delete delta, resource kind: %s, key: %s",
254+
resource.ResourceKind().ToString(), resource.ResourceKey())
260255
if err := s.indexer.Delete(resource); err != nil {
261256
logger.Errorf("failed to delete resource from informer, cause %v, resource: %s,", err, resource.String())
262257
return err
@@ -267,6 +262,31 @@ func (s *informer) HandleDeltas(obj interface{}, _ bool) error {
267262
return nil
268263
}
269264

265+
func (s *informer) toResource(obj interface{}) (model.Resource, error) {
266+
object := obj
267+
if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok {
268+
logger.Debugf("informer resolved tombstone object during delete handling, key: %s", tombstone.Key)
269+
object = tombstone.Obj
270+
}
271+
if resource, ok := object.(model.Resource); ok {
272+
return resource, nil
273+
}
274+
if s.transform != nil {
275+
transformed, err := s.transform(object)
276+
if err != nil {
277+
return nil, err
278+
}
279+
if resource, ok := transformed.(model.Resource); ok {
280+
return resource, nil
281+
}
282+
object = transformed
283+
}
284+
if object == nil {
285+
return nil, bizerror.NewAssertionError("Resource", "nil")
286+
}
287+
return nil, bizerror.NewAssertionError("Resource", reflect.TypeOf(object).Name())
288+
}
289+
270290
// EmitEvent emits an event to the event bus.
271291
func (s *informer) EmitEvent(typ cache.DeltaType, oldObj model.Resource, newObj model.Resource) {
272292
event := events.NewResourceChangedEvent(typ, oldObj, newObj)

pkg/core/controller/listwatcher.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,9 @@ type ResourceListerWatcher interface {
3131
// return nil if there is no need to transform, see cache.SharedInformer for detail
3232
TransformFunc() cache.TransformFunc
3333
}
34+
35+
// ResourceKeyProvider can be optionally implemented by a ResourceListerWatcher when
36+
// raw watch objects need a key that is consistent with the transformed resource key.
37+
type ResourceKeyProvider interface {
38+
KeyFunc() cache.KeyFunc
39+
}

0 commit comments

Comments
 (0)