@@ -137,7 +137,7 @@ with other commands like stop, start, or delete.`,
137137 fmt .Print (breverrors .WrapAndTrace (err ))
138138 }
139139
140- cmd .Flags ().BoolVar (& showAll , "all" , false , "show all workspaces in org" )
140+ cmd .Flags ().BoolVar (& showAll , "all" , false , "show all instances and external nodes in org" )
141141 cmd .Flags ().BoolVar (& jsonOutput , "json" , false , "output as JSON" )
142142
143143 return cmd
@@ -452,9 +452,13 @@ func (ls Ls) RunWorkspaces(org *entity.Organization, user *entity.User, showAll
452452 var allWorkspaces []entity.Workspace
453453 var wsErr error
454454 var gpuLookup map [string ]string
455+ var nodes []* nodev1.ExternalNode
455456
456457 var wg sync.WaitGroup
457458 wg .Add (2 )
459+ if showAll {
460+ wg .Add (1 )
461+ }
458462 go func () {
459463 defer wg .Done ()
460464 allWorkspaces , wsErr = ls .lsStore .GetWorkspaces (org .ID , nil )
@@ -463,6 +467,18 @@ func (ls Ls) RunWorkspaces(org *entity.Organization, user *entity.User, showAll
463467 defer wg .Done ()
464468 gpuLookup = buildGPULookup (ls .lsStore )
465469 }()
470+ if showAll {
471+ go func () {
472+ defer wg .Done ()
473+ var err error
474+ nodes , err = ls .listNodes (org )
475+ if err != nil {
476+ if featureflag .Debug () {
477+ _ , _ = fmt .Fprintf (os .Stderr , "debug: failed to list external nodes: %v\n " , err )
478+ }
479+ }
480+ }()
481+ }
466482 wg .Wait ()
467483
468484 if wsErr != nil {
@@ -479,7 +495,7 @@ func (ls Ls) RunWorkspaces(org *entity.Organization, user *entity.User, showAll
479495
480496 // Handle JSON output
481497 if ls .jsonOutput {
482- return ls .outputWorkspacesJSON (workspacesToShow , gpuLookup )
498+ return ls .outputWorkspacesJSON (workspacesToShow , gpuLookup , nodes )
483499 }
484500
485501 // Table output with colors and help text
@@ -489,6 +505,10 @@ func (ls Ls) RunWorkspaces(org *entity.Organization, user *entity.User, showAll
489505 }
490506 if showAll {
491507 ls .ShowAllWorkspaces (org , orgs , user , allWorkspaces , gpuLookup )
508+ if len (nodes ) > 0 {
509+ ls .terminal .Vprintf ("\n You have %d external node(s) in Org %s\n " , len (nodes ), ls .terminal .Yellow (org .Name ))
510+ displayNodesTable (ls .terminal , nodes , ls .piped )
511+ }
492512 } else {
493513 ls .ShowUserWorkspaces (org , orgs , user , allWorkspaces , gpuLookup )
494514 }
@@ -545,11 +565,23 @@ func getInstanceTypeAndKind(w entity.Workspace, gpuLookup map[string]string) (st
545565 return "" , ""
546566}
547567
548- func (ls Ls ) outputWorkspacesJSON (workspaces []entity.Workspace , gpuLookup map [string ]string ) error {
549- var infos []WorkspaceInfo
568+ func toNodeInfos (nodes []* nodev1.ExternalNode ) []NodeInfo {
569+ var infos []NodeInfo
570+ for _ , n := range nodes {
571+ infos = append (infos , NodeInfo {
572+ Name : n .GetName (),
573+ OrgID : n .GetOrganizationId (),
574+ Status : nodeConnectionStatus (n ),
575+ })
576+ }
577+ return infos
578+ }
579+
580+ func (ls Ls ) outputWorkspacesJSON (workspaces []entity.Workspace , gpuLookup map [string ]string , nodes []* nodev1.ExternalNode ) error {
581+ var wsInfos []WorkspaceInfo
550582 for _ , w := range workspaces {
551583 instanceType , instanceKind := getInstanceTypeAndKind (w , gpuLookup )
552- infos = append (infos , WorkspaceInfo {
584+ wsInfos = append (wsInfos , WorkspaceInfo {
553585 Name : w .Name ,
554586 ID : w .ID ,
555587 Status : getWorkspaceDisplayStatus (w ),
@@ -561,7 +593,25 @@ func (ls Ls) outputWorkspacesJSON(workspaces []entity.Workspace, gpuLookup map[s
561593 GPU : getGPUForInstance (w , gpuLookup ),
562594 })
563595 }
564- output , err := json .MarshalIndent (infos , "" , " " )
596+
597+ var result any
598+ if nodes != nil {
599+ result = struct {
600+ Workspaces []WorkspaceInfo `json:"workspaces"`
601+ Nodes []NodeInfo `json:"nodes"`
602+ }{
603+ Workspaces : wsInfos ,
604+ Nodes : toNodeInfos (nodes ),
605+ }
606+ } else {
607+ result = struct {
608+ Workspaces []WorkspaceInfo `json:"workspaces"`
609+ }{
610+ Workspaces : wsInfos ,
611+ }
612+ }
613+
614+ output , err := json .MarshalIndent (result , "" , " " )
565615 if err != nil {
566616 return breverrors .WrapAndTrace (err )
567617 }
@@ -727,10 +777,9 @@ func getStatusColoredText(t *terminal.Terminal, status string) string {
727777
728778// NodeInfo represents external node data for JSON output.
729779type NodeInfo struct {
730- Name string `json:"name"`
731- ExternalNodeID string `json:"external_node_id"`
732- OrgID string `json:"org_id"`
733- Status string `json:"status"`
780+ Name string `json:"name"`
781+ OrgID string `json:"org_id"`
782+ Status string `json:"status"`
734783}
735784
736785func (ls Ls ) listNodes (org * entity.Organization ) ([]* nodev1.ExternalNode , error ) {
@@ -766,53 +815,33 @@ func (ls Ls) RunNodes(org *entity.Organization) error {
766815 if ls .jsonOutput {
767816 return ls .outputNodesJSON (nodes )
768817 }
769- if ls .piped {
770- displayNodesTablePlain (nodes )
771- return nil
818+ if ! ls .piped {
819+ ls .terminal .Vprintf ("\n You have %d external node(s) in Org %s\n " , len (nodes ), ls .terminal .Yellow (org .Name ))
772820 }
773-
774- ls .terminal .Vprintf ("\n You have %d external node(s) in Org %s\n " , len (nodes ), ls .terminal .Yellow (org .Name ))
775- displayNodesTable (ls .terminal , nodes )
821+ displayNodesTable (ls .terminal , nodes , ls .piped )
776822 return nil
777823}
778824
779825func (ls Ls ) outputNodesJSON (nodes []* nodev1.ExternalNode ) error {
780- var infos []NodeInfo
781- for _ , n := range nodes {
782- infos = append (infos , NodeInfo {
783- Name : n .GetName (),
784- ExternalNodeID : n .GetExternalNodeId (),
785- OrgID : n .GetOrganizationId (),
786- Status : nodeConnectionStatus (n ),
787- })
788- }
789- output , err := json .MarshalIndent (infos , "" , " " )
826+ output , err := json .MarshalIndent (toNodeInfos (nodes ), "" , " " )
790827 if err != nil {
791828 return breverrors .WrapAndTrace (err )
792829 }
793830 fmt .Println (string (output ))
794831 return nil
795832}
796833
797- func displayNodesTable (t * terminal.Terminal , nodes []* nodev1.ExternalNode ) {
834+ func displayNodesTable (t * terminal.Terminal , nodes []* nodev1.ExternalNode , isPiped bool ) {
798835 ta := table .NewWriter ()
799836 ta .SetOutputMirror (os .Stdout )
800837 ta .Style ().Options = getBrevTableOptions ()
801- ta .AppendHeader (table.Row {"NAME" , "NODE ID" , "DEVICE ID" , " STATUS" })
838+ ta .AppendHeader (table.Row {"NAME" , "STATUS" })
802839 for _ , n := range nodes {
803840 status := nodeConnectionStatus (n )
804- ta .AppendRows ([]table.Row {{n .GetName (), n .GetExternalNodeId (), n .GetDeviceId (), getStatusColoredText (t , status )}})
805- }
806- ta .Render ()
807- }
808-
809- func displayNodesTablePlain (nodes []* nodev1.ExternalNode ) {
810- ta := table .NewWriter ()
811- ta .SetOutputMirror (os .Stdout )
812- ta .Style ().Options = getBrevTableOptions ()
813- ta .AppendHeader (table.Row {"NAME" , "NODE ID" , "DEVICE ID" , "STATUS" })
814- for _ , n := range nodes {
815- ta .AppendRows ([]table.Row {{n .GetName (), n .GetExternalNodeId (), n .GetDeviceId (), nodeConnectionStatus (n )}})
841+ if ! isPiped {
842+ status = getStatusColoredText (t , status )
843+ }
844+ ta .AppendRows ([]table.Row {{n .GetName (), status }})
816845 }
817846 ta .Render ()
818847}
0 commit comments