Skip to content

Commit db011e3

Browse files
committed
STAC-24504: fix domain/layer mapping for topology inspect
1 parent 6095aa7 commit db011e3

2 files changed

Lines changed: 40 additions & 84 deletions

File tree

cmd/topology/topology_inspect.go

Lines changed: 29 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"github.com/stackvista/stackstate-cli/internal/printer"
1414
)
1515

16+
const UNKNOWN = "unknown"
17+
1618
type InspectArgs struct {
1719
ComponentType string
1820
Tags []string
@@ -154,15 +156,13 @@ type Component struct {
154156
Properties map[string]interface{} `json:"properties"`
155157
Layer map[string]interface{} `json:"layer"`
156158
Domain map[string]interface{} `json:"domain"`
157-
Environment map[string]interface{} `json:"environment,omitempty"`
158159
Link string `json:"link"`
159160
}
160161

161162
type ComponentMetadata struct {
162163
ComponentTypes map[string]string
163-
Layers map[int64]string
164-
Domains map[int64]string
165-
Environments map[int64]string
164+
Layers map[string]string
165+
Domains map[string]string
166166
}
167167

168168
// handleSnapshotError checks if the response is a typed error by examining the _type discriminator
@@ -255,31 +255,20 @@ func parseSnapshotResponse(
255255
// all metadata categories in a single loop.
256256
var metadataFieldMapping = []struct {
257257
field string
258-
setter func(*ComponentMetadata, interface{}) error
258+
setter func(*ComponentMetadata, interface{})
259259
}{
260-
{"componentTypes", parseComponentTypesField},
261-
{"layers", func(m *ComponentMetadata, val interface{}) error {
262-
m.Layers = parseMetadataField(val)
263-
return nil
264-
}},
265-
{"domains", func(m *ComponentMetadata, val interface{}) error {
266-
m.Domains = parseMetadataField(val)
267-
return nil
268-
}},
269-
{"environments", func(m *ComponentMetadata, val interface{}) error {
270-
m.Environments = parseMetadataField(val)
271-
return nil
272-
}},
260+
{"componentTypes", func(m *ComponentMetadata, val interface{}) { m.ComponentTypes = parseMetadataByIdentifier(val) }},
261+
{"layers", func(m *ComponentMetadata, val interface{}) { m.Layers = parseMetadataByIdentifier(val) }},
262+
{"domains", func(m *ComponentMetadata, val interface{}) { m.Domains = parseMetadataByIdentifier(val) }},
273263
}
274264

275-
// parseMetadata extracts component type, layer, domain, and environment metadata
265+
// parseMetadata extracts component type, layer, and domain metadata
276266
// from the opaque Snapshot response using a table-driven approach.
277267
func parseMetadata(respMap map[string]interface{}) ComponentMetadata {
278268
metadata := ComponentMetadata{
279269
ComponentTypes: make(map[string]string),
280-
Layers: make(map[int64]string),
281-
Domains: make(map[int64]string),
282-
Environments: make(map[int64]string),
270+
Layers: make(map[string]string),
271+
Domains: make(map[string]string),
283272
}
284273

285274
metadataMap, ok := respMap["metadata"].(map[string]interface{})
@@ -289,63 +278,32 @@ func parseMetadata(respMap map[string]interface{}) ComponentMetadata {
289278

290279
for _, mapping := range metadataFieldMapping {
291280
if fieldValue, ok := metadataMap[mapping.field]; ok {
292-
mapping.setter(&metadata, fieldValue) //nolint:errcheck
281+
mapping.setter(&metadata, fieldValue)
293282
}
294283
}
295284

296285
return metadata
297286
}
298287

299-
// parseComponentTypesField extracts component types from metadata, using identifier as key
300-
func parseComponentTypesField(m *ComponentMetadata, metadataValue interface{}) error {
301-
if metadataValue == nil {
302-
return nil
303-
}
304-
305-
items, ok := metadataValue.([]interface{})
306-
if !ok {
307-
return nil
308-
}
309-
310-
for _, item := range items {
311-
if itemMap, ok := item.(map[string]interface{}); ok {
312-
var key string
313-
if identifier, ok := itemMap["identifier"].(string); ok {
314-
key = identifier
315-
} else {
316-
continue
317-
}
318-
319-
if name, ok := itemMap["name"].(string); ok {
320-
m.ComponentTypes[key] = name
321-
}
322-
}
323-
}
324-
325-
return nil
326-
}
327-
328-
// parseMetadataField extracts id/name pairs from a metadata field.
329-
// Each item in the slice should have "id" and "name" fields.
330-
func parseMetadataField(metadataValue interface{}) map[int64]string {
331-
result := make(map[int64]string)
288+
// parseMetadataByIdentifier extracts metadata items by identifier.
289+
func parseMetadataByIdentifier(metadataValue interface{}) map[string]string {
290+
result := make(map[string]string)
332291

333292
if metadataValue == nil {
334293
return result
335294
}
336295

337-
// The JSON decoder produces []interface{} for arrays
338296
items, ok := metadataValue.([]interface{})
339297
if !ok {
340298
return result
341299
}
342300

343301
for _, item := range items {
344302
if itemMap, ok := item.(map[string]interface{}); ok {
345-
id, idOk := itemMap["id"].(float64)
303+
identifier, idOk := itemMap["identifier"].(string)
346304
name, nameOk := itemMap["name"].(string)
347305
if idOk && nameOk {
348-
result[int64(id)] = name
306+
result[identifier] = name
349307
}
350308
}
351309
}
@@ -373,7 +331,7 @@ func parseComponentFromMap(compMap map[string]interface{}, metadata ComponentMet
373331
if typeName, found := metadata.ComponentTypes[typeIdentifier]; found {
374332
comp.Type = typeName
375333
} else {
376-
comp.Type = "Unknown" //nolint:goconst
334+
comp.Type = UNKNOWN
377335
}
378336
}
379337

@@ -400,10 +358,9 @@ func parseComponentFromMap(compMap map[string]interface{}, metadata ComponentMet
400358
comp.Properties = propertiesRaw
401359
}
402360

403-
// Parse layer, domain, and environment references
404-
comp.Layer = parseComponentReference(compMap, "layer", metadata.Layers)
405-
comp.Domain = parseComponentReference(compMap, "domain", metadata.Domains)
406-
comp.Environment = parseComponentReference(compMap, "environment", metadata.Environments)
361+
// Parse layer and domain references
362+
comp.Layer = parseComponentReference(compMap, "layerIdentifier", metadata.Layers)
363+
comp.Domain = parseComponentReference(compMap, "domainIdentifier", metadata.Domains)
407364

408365
// Build link
409366
if len(comp.Identifiers) > 0 {
@@ -413,19 +370,18 @@ func parseComponentFromMap(compMap map[string]interface{}, metadata ComponentMet
413370
return comp
414371
}
415372

416-
// parseComponentReference extracts a reference field (layer, domain, or environment)
373+
// parseComponentReference extracts a reference field (layer or domain)
417374
// from a component and looks up its name in the provided metadata map.
418-
// Returns a map with "id" and "name" keys, or nil if the field is not present.
419-
func parseComponentReference(compMap map[string]interface{}, fieldName string, metadataMap map[int64]string) map[string]interface{} {
420-
if refID, ok := compMap[fieldName].(float64); ok {
421-
refIDInt := int64(refID)
422-
refName := "Unknown"
423-
if name, found := metadataMap[refIDInt]; found {
375+
// Returns a map with "identifier" and "name" keys, or nil if the field is not present.
376+
func parseComponentReference(compMap map[string]interface{}, identifierFieldName string, metadataMap map[string]string) map[string]interface{} {
377+
if refIdentifier, ok := compMap[identifierFieldName].(string); ok {
378+
refName := UNKNOWN
379+
if name, found := metadataMap[refIdentifier]; found {
424380
refName = name
425381
}
426382
return map[string]interface{}{
427-
"id": refIDInt,
428-
"name": refName,
383+
"identifier": refIdentifier,
384+
"name": refName,
429385
}
430386
}
431387
return nil

cmd/topology/topology_test_helper.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ func mockSnapshotResponse() sts.QuerySnapshotResult {
1212
"_type": "ViewSnapshot",
1313
"components": []interface{}{
1414
map[string]interface{}{
15-
"id": float64(229404307680647),
16-
"name": "test-component",
17-
"typeIdentifier": "urn:test:component-type:test",
18-
"layer": float64(186771622698247),
19-
"domain": float64(209616858431909),
20-
"identifiers": []interface{}{"urn:test:component:1"},
21-
"tags": []interface{}{"service.namespace:test"},
15+
"id": float64(229404307680647),
16+
"name": "test-component",
17+
"typeIdentifier": "urn:test:component-type:test",
18+
"layerIdentifier": "urn:test:layer:test",
19+
"domainIdentifier": "urn:test:domain:test",
20+
"identifiers": []interface{}{"urn:test:component:1"},
21+
"tags": []interface{}{"service.namespace:test"},
2222
"state": map[string]interface{}{
2323
"healthState": "CRITICAL",
2424
},
@@ -33,14 +33,14 @@ func mockSnapshotResponse() sts.QuerySnapshotResult {
3333
},
3434
"layers": []interface{}{
3535
map[string]interface{}{
36-
"id": float64(186771622698247),
37-
"name": "Test Layer",
36+
"identifier": "urn:test:layer:test",
37+
"name": "Test Layer",
3838
},
3939
},
4040
"domains": []interface{}{
4141
map[string]interface{}{
42-
"id": float64(209616858431909),
43-
"name": "Test Domain",
42+
"identifier": "urn:test:domain:test",
43+
"name": "Test Domain",
4444
},
4545
},
4646
},

0 commit comments

Comments
 (0)