@@ -18,6 +18,7 @@ import (
1818 apierrors "k8s.io/apimachinery/pkg/api/errors"
1919 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020 "k8s.io/apimachinery/pkg/types"
21+ utilvalidation "k8s.io/apimachinery/pkg/util/validation"
2122 "sigs.k8s.io/controller-runtime/pkg/client"
2223 ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
2324)
@@ -32,35 +33,46 @@ func NewAgentsHandler(base *Base) *AgentsHandler {
3233 return & AgentsHandler {Base : base }
3334}
3435
35- // HandleListAgents handles GET /api/agents requests using database
36+ // HandleListAgents handles GET /api/agents requests using database.
37+ // Optional query param: namespace=<ns>.
3638func (h * AgentsHandler ) HandleListAgents (w ErrorResponseWriter , r * http.Request ) {
3739 log := ctrllog .FromContext (r .Context ()).WithName ("agents-handler" ).WithValues ("operation" , "list-db" )
3840
39- if err := Check (h .Authorizer , r , auth.Resource {Type : "Agent" }); err != nil {
40- w .RespondWithError (err )
41+ namespace := r .URL .Query ().Get ("namespace" )
42+ if namespace == "" {
43+ h .handleListAgents (w , r , log )
4144 return
4245 }
4346
44- agentList := & v1alpha2.AgentList {}
45- if err := h .KubeClient .List (r .Context (), agentList ); err != nil {
46- w .RespondWithError (errors .NewInternalServerError ("Failed to list Agents from Kubernetes" , err ))
47+ if strings .TrimSpace (namespace ) != namespace {
48+ w .RespondWithError (errors .NewBadRequestError (
49+ fmt .Sprintf ("invalid namespace %q: must not contain leading or trailing whitespace" , namespace ),
50+ nil ,
51+ ))
4752 return
4853 }
4954
50- agentsWithID := make ([]api.AgentResponse , 0 )
51- h .appendAgentResponses (r .Context (), log , agentObjects (agentList .Items ), & agentsWithID )
55+ if errs := utilvalidation .IsDNS1123Label (namespace ); len (errs ) > 0 {
56+ w .RespondWithError (errors .NewBadRequestError (
57+ fmt .Sprintf ("invalid namespace %q: %s" , namespace , strings .Join (errs , "; " )),
58+ nil ,
59+ ))
60+ return
61+ }
5262
53- harnessList := & v1alpha2.AgentHarnessList {}
54- if err := h .KubeClient .List (r .Context (), harnessList ); err != nil {
55- w .RespondWithError (errors .NewInternalServerError ("Failed to list AgentHarness resources from Kubernetes" , err ))
63+ h .handleListAgents (w , r , log .WithValues ("namespace" , namespace ), client .InNamespace (namespace ))
64+ }
65+
66+ func (h * AgentsHandler ) handleListAgents (w ErrorResponseWriter , r * http.Request , log logr.Logger , opts ... client.ListOption ) {
67+ if err := Check (h .Authorizer , r , auth.Resource {Type : "Agent" }); err != nil {
68+ w .RespondWithError (err )
5669 return
5770 }
58- for i := range harnessList .Items {
59- sb := & harnessList .Items [i ]
60- if sb .Spec .Backend != v1alpha2 .AgentHarnessBackendOpenClaw && sb .Spec .Backend != v1alpha2 .AgentHarnessBackendNemoClaw {
61- continue
62- }
63- agentsWithID = append (agentsWithID , h .openshellAgentHarnessAgentResponse (r .Context (), log , sb ))
71+
72+ agentsWithID , err := h .listAgentResponses (r .Context (), log , opts ... )
73+ if err != nil {
74+ w .RespondWithError (err )
75+ return
6476 }
6577
6678 log .Info ("Successfully listed agents" , "count" , len (agentsWithID ))
@@ -91,6 +103,33 @@ func (h *AgentsHandler) HandleListSandboxAgents(w ErrorResponseWriter, r *http.R
91103 RespondWithJSON (w , http .StatusOK , data )
92104}
93105
106+ // listAgentResponses fetches Agent and AgentHarness resources, applies the
107+ // provided list options (e.g. client.InNamespace), and returns the merged
108+ // slice of AgentResponse values.
109+ func (h * AgentsHandler ) listAgentResponses (ctx context.Context , log logr.Logger , opts ... client.ListOption ) ([]api.AgentResponse , error ) {
110+ agentList := & v1alpha2.AgentList {}
111+ if err := h .KubeClient .List (ctx , agentList , opts ... ); err != nil {
112+ return nil , errors .NewInternalServerError ("Failed to list Agents from Kubernetes" , err )
113+ }
114+
115+ harnessList := & v1alpha2.AgentHarnessList {}
116+ if err := h .KubeClient .List (ctx , harnessList , opts ... ); err != nil {
117+ return nil , errors .NewInternalServerError ("Failed to list AgentHarness resources from Kubernetes" , err )
118+ }
119+
120+ result := make ([]api.AgentResponse , 0 , len (agentList .Items )+ len (harnessList .Items ))
121+ h .appendAgentResponses (ctx , log , agentObjects (agentList .Items ), & result )
122+ for i := range harnessList .Items {
123+ sb := & harnessList .Items [i ]
124+ if sb .Spec .Backend != v1alpha2 .AgentHarnessBackendOpenClaw && sb .Spec .Backend != v1alpha2 .AgentHarnessBackendNemoClaw {
125+ continue
126+ }
127+ result = append (result , h .openshellAgentHarnessAgentResponse (ctx , log , sb ))
128+ }
129+
130+ return result , nil
131+ }
132+
94133func (h * AgentsHandler ) appendAgentResponses (
95134 ctx context.Context ,
96135 log logr.Logger ,
0 commit comments