From 84f3ae51f8ace9c05e75782cf45356ceaef91998 Mon Sep 17 00:00:00 2001 From: Rafael Garcia Date: Mon, 16 Feb 2026 22:04:54 -0500 Subject: [PATCH] feat: add metadata and state filtering to GET /instances Add query parameters to the list instances endpoint so callers can filter by instance state and/or user-defined metadata key-value pairs: GET /instances?state=Running&metadata[team]=backend&metadata[env]=staging Uses OpenAPI deepObject style for the metadata parameter, which oapi-codegen deserializes into map[string]string automatically. Multiple metadata entries are ANDed -- an instance must match all specified key-value pairs. Adds ListInstancesFilter type with a Matches() method, updates the Manager interface to accept *ListInstancesFilter, and wires it through the API handler. Co-authored-by: Cursor --- cmd/api/api/instances.go | 17 +- cmd/api/main.go | 2 +- lib/builds/manager_test.go | 6 +- lib/instances/filter_test.go | 261 ++++++++++++++++ lib/instances/manager.go | 24 +- lib/instances/manager_test.go | 2 +- lib/instances/qemu_test.go | 2 +- lib/instances/resource_limits_test.go | 2 +- lib/instances/types.go | 26 ++ lib/oapi/oapi.go | 434 +++++++++++++++----------- openapi.yaml | 20 ++ 11 files changed, 604 insertions(+), 192 deletions(-) create mode 100644 lib/instances/filter_test.go diff --git a/cmd/api/api/instances.go b/cmd/api/api/instances.go index ca7c2fbc..10da1074 100644 --- a/cmd/api/api/instances.go +++ b/cmd/api/api/instances.go @@ -21,11 +21,24 @@ import ( "github.com/samber/lo" ) -// ListInstances lists all instances +// ListInstances lists instances, optionally filtered by state and/or metadata. func (s *ApiService) ListInstances(ctx context.Context, request oapi.ListInstancesRequestObject) (oapi.ListInstancesResponseObject, error) { log := logger.FromContext(ctx) - domainInsts, err := s.InstanceManager.ListInstances(ctx) + // Convert OAPI params to domain filter + var filter *instances.ListInstancesFilter + if request.Params.State != nil || request.Params.Metadata != nil { + filter = &instances.ListInstancesFilter{} + if request.Params.State != nil { + state := instances.State(*request.Params.State) + filter.State = &state + } + if request.Params.Metadata != nil { + filter.Metadata = *request.Params.Metadata + } + } + + domainInsts, err := s.InstanceManager.ListInstances(ctx, filter) if err != nil { log.ErrorContext(ctx, "failed to list instances", "error", err) return oapi.ListInstances500JSONResponse{ diff --git a/cmd/api/main.go b/cmd/api/main.go index 8d3c7cd6..f7651475 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -171,7 +171,7 @@ func run() error { // Include Unknown state: we couldn't confirm their state, but they might still // have a running VMM. Better to leave a stale TAP than crash a running VM. var preserveTAPs []string - allInstances, err := app.InstanceManager.ListInstances(app.Ctx) + allInstances, err := app.InstanceManager.ListInstances(app.Ctx, nil) if err != nil { // On error, skip TAP cleanup entirely to avoid crashing running VMs. // Pass nil to Initialize to skip cleanup. diff --git a/lib/builds/manager_test.go b/lib/builds/manager_test.go index b8863006..af5b4686 100644 --- a/lib/builds/manager_test.go +++ b/lib/builds/manager_test.go @@ -37,10 +37,12 @@ func newMockInstanceManager() *mockInstanceManager { } } -func (m *mockInstanceManager) ListInstances(ctx context.Context) ([]instances.Instance, error) { +func (m *mockInstanceManager) ListInstances(ctx context.Context, filter *instances.ListInstancesFilter) ([]instances.Instance, error) { var result []instances.Instance for _, inst := range m.instances { - result = append(result, *inst) + if filter == nil || filter.Matches(inst) { + result = append(result, *inst) + } } return result, nil } diff --git a/lib/instances/filter_test.go b/lib/instances/filter_test.go new file mode 100644 index 00000000..71a1c98e --- /dev/null +++ b/lib/instances/filter_test.go @@ -0,0 +1,261 @@ +package instances + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "testing" + "time" + + "github.com/kernel/hypeman/lib/hypervisor" + "github.com/kernel/hypeman/lib/paths" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestListInstancesFilter_Matches(t *testing.T) { + running := StateRunning + stopped := StateStopped + + inst := &Instance{ + StoredMetadata: StoredMetadata{ + Id: "inst-1", + Name: "web-server", + Image: "nginx:latest", + Metadata: map[string]string{ + "team": "backend", + "env": "staging", + }, + }, + State: StateRunning, + } + + tests := []struct { + name string + filter *ListInstancesFilter + want bool + }{ + { + name: "nil filter matches everything", + filter: nil, + want: true, + }, + { + name: "empty filter matches everything", + filter: &ListInstancesFilter{}, + want: true, + }, + { + name: "state filter matches", + filter: &ListInstancesFilter{State: &running}, + want: true, + }, + { + name: "state filter does not match", + filter: &ListInstancesFilter{State: &stopped}, + want: false, + }, + { + name: "single metadata key matches", + filter: &ListInstancesFilter{ + Metadata: map[string]string{"team": "backend"}, + }, + want: true, + }, + { + name: "single metadata key wrong value", + filter: &ListInstancesFilter{ + Metadata: map[string]string{"team": "frontend"}, + }, + want: false, + }, + { + name: "metadata key does not exist", + filter: &ListInstancesFilter{ + Metadata: map[string]string{"project": "alpha"}, + }, + want: false, + }, + { + name: "multiple metadata keys all match", + filter: &ListInstancesFilter{ + Metadata: map[string]string{ + "team": "backend", + "env": "staging", + }, + }, + want: true, + }, + { + name: "multiple metadata keys partial match", + filter: &ListInstancesFilter{ + Metadata: map[string]string{ + "team": "backend", + "env": "production", + }, + }, + want: false, + }, + { + name: "state and metadata combined match", + filter: &ListInstancesFilter{ + State: &running, + Metadata: map[string]string{"team": "backend"}, + }, + want: true, + }, + { + name: "state matches but metadata does not", + filter: &ListInstancesFilter{ + State: &running, + Metadata: map[string]string{"team": "frontend"}, + }, + want: false, + }, + { + name: "metadata matches but state does not", + filter: &ListInstancesFilter{ + State: &stopped, + Metadata: map[string]string{"team": "backend"}, + }, + want: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := tc.filter.Matches(inst) + assert.Equal(t, tc.want, got) + }) + } +} + +func TestListInstancesFilter_Matches_NilMetadata(t *testing.T) { + inst := &Instance{ + StoredMetadata: StoredMetadata{ + Id: "inst-2", + Metadata: nil, + }, + State: StateRunning, + } + + filter := &ListInstancesFilter{ + Metadata: map[string]string{"team": "backend"}, + } + assert.False(t, filter.Matches(inst), "should not match when instance has no metadata") +} + +// TestListInstances_WithFilter exercises the full ListInstances path using +// on-disk metadata files (no KVM required). +func TestListInstances_WithFilter(t *testing.T) { + tmpDir := t.TempDir() + p := paths.New(tmpDir) + + mgr := &manager{paths: p} + + // Create three instances with different metadata on disk + instances := []StoredMetadata{ + { + Id: "inst-a", + Name: "web", + Image: "nginx:latest", + Metadata: map[string]string{"team": "backend", "env": "prod"}, + CreatedAt: time.Now(), + HypervisorType: hypervisor.TypeCloudHypervisor, + SocketPath: "/nonexistent/a.sock", + DataDir: p.InstanceDir("inst-a"), + }, + { + Id: "inst-b", + Name: "worker", + Image: "python:3", + Metadata: map[string]string{"team": "backend", "env": "staging"}, + CreatedAt: time.Now(), + HypervisorType: hypervisor.TypeCloudHypervisor, + SocketPath: "/nonexistent/b.sock", + DataDir: p.InstanceDir("inst-b"), + }, + { + Id: "inst-c", + Name: "frontend", + Image: "node:20", + Metadata: map[string]string{"team": "frontend", "env": "prod"}, + CreatedAt: time.Now(), + HypervisorType: hypervisor.TypeCloudHypervisor, + SocketPath: "/nonexistent/c.sock", + DataDir: p.InstanceDir("inst-c"), + }, + } + + for _, stored := range instances { + require.NoError(t, mgr.ensureDirectories(stored.Id)) + data, err := json.MarshalIndent(&metadata{StoredMetadata: stored}, "", " ") + require.NoError(t, err) + require.NoError(t, os.WriteFile(filepath.Join(p.InstanceDir(stored.Id), "metadata.json"), data, 0644)) + } + + ctx := context.Background() + + t.Run("no filter returns all", func(t *testing.T) { + result, err := mgr.ListInstances(ctx, nil) + require.NoError(t, err) + assert.Len(t, result, 3) + }) + + t.Run("filter by single metadata key", func(t *testing.T) { + result, err := mgr.ListInstances(ctx, &ListInstancesFilter{ + Metadata: map[string]string{"team": "backend"}, + }) + require.NoError(t, err) + assert.Len(t, result, 2) + names := []string{result[0].Name, result[1].Name} + assert.ElementsMatch(t, []string{"web", "worker"}, names) + }) + + t.Run("filter by two metadata keys", func(t *testing.T) { + result, err := mgr.ListInstances(ctx, &ListInstancesFilter{ + Metadata: map[string]string{"team": "backend", "env": "prod"}, + }) + require.NoError(t, err) + require.Len(t, result, 1) + assert.Equal(t, "web", result[0].Name) + }) + + t.Run("filter by metadata with no matches", func(t *testing.T) { + result, err := mgr.ListInstances(ctx, &ListInstancesFilter{ + Metadata: map[string]string{"team": "devops"}, + }) + require.NoError(t, err) + assert.Empty(t, result) + }) + + t.Run("filter by state", func(t *testing.T) { + // All instances have no socket so they're Stopped + stopped := StateStopped + result, err := mgr.ListInstances(ctx, &ListInstancesFilter{ + State: &stopped, + }) + require.NoError(t, err) + assert.Len(t, result, 3) + + running := StateRunning + result, err = mgr.ListInstances(ctx, &ListInstancesFilter{ + State: &running, + }) + require.NoError(t, err) + assert.Empty(t, result) + }) + + t.Run("filter by state and metadata combined", func(t *testing.T) { + stopped := StateStopped + result, err := mgr.ListInstances(ctx, &ListInstancesFilter{ + State: &stopped, + Metadata: map[string]string{"env": "prod"}, + }) + require.NoError(t, err) + assert.Len(t, result, 2) + names := []string{result[0].Name, result[1].Name} + assert.ElementsMatch(t, []string{"web", "frontend"}, names) + }) +} diff --git a/lib/instances/manager.go b/lib/instances/manager.go index 6081332d..3c764d13 100644 --- a/lib/instances/manager.go +++ b/lib/instances/manager.go @@ -18,7 +18,7 @@ import ( ) type Manager interface { - ListInstances(ctx context.Context) ([]Instance, error) + ListInstances(ctx context.Context, filter *ListInstancesFilter) ([]Instance, error) CreateInstance(ctx context.Context, req CreateInstanceRequest) (*Instance, error) // GetInstance returns an instance by ID, name, or ID prefix. // Lookup order: exact ID match -> exact name match -> ID prefix match. @@ -214,11 +214,25 @@ func (m *manager) StartInstance(ctx context.Context, id string, req StartInstanc return m.startInstance(ctx, id, req) } -// ListInstances returns all instances -func (m *manager) ListInstances(ctx context.Context) ([]Instance, error) { +// ListInstances returns instances, optionally filtered by the given criteria. +// Pass nil to return all instances. +func (m *manager) ListInstances(ctx context.Context, filter *ListInstancesFilter) ([]Instance, error) { // No lock - eventual consistency is acceptable for list operations. // State is derived dynamically, so list is always reasonably current. - return m.listInstances(ctx) + all, err := m.listInstances(ctx) + if err != nil { + return nil, err + } + if filter == nil { + return all, nil + } + filtered := make([]Instance, 0, len(all)) + for i := range all { + if filter.Matches(&all[i]) { + filtered = append(filtered, all[i]) + } + } + return filtered, nil } // GetInstance returns an instance by ID, name, or ID prefix. @@ -240,7 +254,7 @@ func (m *manager) GetInstance(ctx context.Context, idOrName string) (*Instance, } // 2. List all instances for name and prefix matching - instances, err := m.ListInstances(ctx) + instances, err := m.ListInstances(ctx, nil) if err != nil { return nil, err } diff --git a/lib/instances/manager_test.go b/lib/instances/manager_test.go index fbc27fef..0811ca2c 100644 --- a/lib/instances/manager_test.go +++ b/lib/instances/manager_test.go @@ -321,7 +321,7 @@ func TestBasicEndToEnd(t *testing.T) { assert.Equal(t, StateRunning, retrieved.State) // List instances - instances, err := manager.ListInstances(ctx) + instances, err := manager.ListInstances(ctx, nil) require.NoError(t, err) assert.Len(t, instances, 1) assert.Equal(t, inst.Id, instances[0].Id) diff --git a/lib/instances/qemu_test.go b/lib/instances/qemu_test.go index 05f1f9fd..5e2421f6 100644 --- a/lib/instances/qemu_test.go +++ b/lib/instances/qemu_test.go @@ -316,7 +316,7 @@ func TestQEMUBasicEndToEnd(t *testing.T) { assert.Equal(t, StateRunning, retrieved.State) // List instances - instances, err := manager.ListInstances(ctx) + instances, err := manager.ListInstances(ctx, nil) require.NoError(t, err) assert.Len(t, instances, 1) assert.Equal(t, inst.Id, instances[0].Id) diff --git a/lib/instances/resource_limits_test.go b/lib/instances/resource_limits_test.go index 7337df8a..95f01f3e 100644 --- a/lib/instances/resource_limits_test.go +++ b/lib/instances/resource_limits_test.go @@ -203,7 +203,7 @@ func TestResourceLimits_ZeroMeansUnlimited(t *testing.T) { // cleanupTestProcesses kills any Cloud Hypervisor processes started during test func cleanupTestProcesses(t *testing.T, mgr *manager) { t.Helper() - instances, err := mgr.ListInstances(context.Background()) + instances, err := mgr.ListInstances(context.Background(), nil) if err != nil { return } diff --git a/lib/instances/types.go b/lib/instances/types.go index 64966c9a..1b270e6a 100644 --- a/lib/instances/types.go +++ b/lib/instances/types.go @@ -114,6 +114,32 @@ func (i *Instance) GetHypervisorType() string { return string(i.HypervisorType) } +// ListInstancesFilter contains optional filters for listing instances. +// All fields are ANDed together: an instance must match every specified filter. +type ListInstancesFilter struct { + State *State // Filter by instance state + Metadata map[string]string // Filter by metadata key-value pairs (all must match) +} + +// Matches returns true if the given instance satisfies all filter criteria. +func (f *ListInstancesFilter) Matches(inst *Instance) bool { + if f == nil { + return true + } + if f.State != nil && inst.State != *f.State { + return false + } + for k, v := range f.Metadata { + if inst.Metadata == nil { + return false + } + if actual, ok := inst.Metadata[k]; !ok || actual != v { + return false + } + } + return true +} + // GPUConfig contains GPU configuration for instance creation type GPUConfig struct { Profile string // vGPU profile name (e.g., "L40S-1Q") diff --git a/lib/oapi/oapi.go b/lib/oapi/oapi.go index 6ce10226..269eb7c0 100644 --- a/lib/oapi/oapi.go +++ b/lib/oapi/oapi.go @@ -879,6 +879,17 @@ type GetBuildEventsParams struct { Follow *bool `form:"follow,omitempty" json:"follow,omitempty"` } +// ListInstancesParams defines parameters for ListInstances. +type ListInstancesParams struct { + // State Filter instances by state (e.g., Running, Stopped) + State *InstanceState `form:"state,omitempty" json:"state,omitempty"` + + // Metadata Filter instances by metadata key-value pairs. Uses deepObject style: + // ?metadata[team]=backend&metadata[env]=staging + // Multiple entries are ANDed together. All specified key-value pairs must match. + Metadata *map[string]string `json:"metadata,omitempty"` +} + // GetInstanceLogsParams defines parameters for GetInstanceLogs. type GetInstanceLogsParams struct { // Tail Number of lines to return from end @@ -1088,7 +1099,7 @@ type ClientInterface interface { GetIngress(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) // ListInstances request - ListInstances(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + ListInstances(ctx context.Context, params *ListInstancesParams, reqEditors ...RequestEditorFn) (*http.Response, error) // CreateInstanceWithBody request with any body CreateInstanceWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1417,8 +1428,8 @@ func (c *Client) GetIngress(ctx context.Context, id string, reqEditors ...Reques return c.Client.Do(req) } -func (c *Client) ListInstances(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { - req, err := NewListInstancesRequest(c.Server) +func (c *Client) ListInstances(ctx context.Context, params *ListInstancesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewListInstancesRequest(c.Server, params) if err != nil { return nil, err } @@ -2333,7 +2344,7 @@ func NewGetIngressRequest(server string, id string) (*http.Request, error) { } // NewListInstancesRequest generates requests for ListInstances -func NewListInstancesRequest(server string) (*http.Request, error) { +func NewListInstancesRequest(server string, params *ListInstancesParams) (*http.Request, error) { var err error serverURL, err := url.Parse(server) @@ -2351,6 +2362,44 @@ func NewListInstancesRequest(server string) (*http.Request, error) { return nil, err } + if params != nil { + queryValues := queryURL.Query() + + if params.State != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "state", runtime.ParamLocationQuery, *params.State); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Metadata != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("deepObject", true, "metadata", runtime.ParamLocationQuery, *params.Metadata); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + req, err := http.NewRequest("GET", queryURL.String(), nil) if err != nil { return nil, err @@ -3245,7 +3294,7 @@ type ClientWithResponsesInterface interface { GetIngressWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetIngressResponse, error) // ListInstancesWithResponse request - ListInstancesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListInstancesResponse, error) + ListInstancesWithResponse(ctx context.Context, params *ListInstancesParams, reqEditors ...RequestEditorFn) (*ListInstancesResponse, error) // CreateInstanceWithBodyWithResponse request with any body CreateInstanceWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateInstanceResponse, error) @@ -4432,8 +4481,8 @@ func (c *ClientWithResponses) GetIngressWithResponse(ctx context.Context, id str } // ListInstancesWithResponse request returning *ListInstancesResponse -func (c *ClientWithResponses) ListInstancesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListInstancesResponse, error) { - rsp, err := c.ListInstances(ctx, reqEditors...) +func (c *ClientWithResponses) ListInstancesWithResponse(ctx context.Context, params *ListInstancesParams, reqEditors ...RequestEditorFn) (*ListInstancesResponse, error) { + rsp, err := c.ListInstances(ctx, params, reqEditors...) if err != nil { return nil, err } @@ -6313,7 +6362,7 @@ type ServerInterface interface { GetIngress(w http.ResponseWriter, r *http.Request, id string) // List instances // (GET /instances) - ListInstances(w http.ResponseWriter, r *http.Request) + ListInstances(w http.ResponseWriter, r *http.Request, params ListInstancesParams) // Create and start instance // (POST /instances) CreateInstance(w http.ResponseWriter, r *http.Request) @@ -6490,7 +6539,7 @@ func (_ Unimplemented) GetIngress(w http.ResponseWriter, r *http.Request, id str // List instances // (GET /instances) -func (_ Unimplemented) ListInstances(w http.ResponseWriter, r *http.Request) { +func (_ Unimplemented) ListInstances(w http.ResponseWriter, r *http.Request, params ListInstancesParams) { w.WriteHeader(http.StatusNotImplemented) } @@ -7098,14 +7147,35 @@ func (siw *ServerInterfaceWrapper) GetIngress(w http.ResponseWriter, r *http.Req // ListInstances operation middleware func (siw *ServerInterfaceWrapper) ListInstances(w http.ResponseWriter, r *http.Request) { + var err error + ctx := r.Context() ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) r = r.WithContext(ctx) + // Parameter object where we will unmarshal all parameters from the context + var params ListInstancesParams + + // ------------- Optional query parameter "state" ------------- + + err = runtime.BindQueryParameter("form", true, false, "state", r.URL.Query(), ¶ms.State) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "state", Err: err}) + return + } + + // ------------- Optional query parameter "metadata" ------------- + + err = runtime.BindQueryParameter("deepObject", true, false, "metadata", r.URL.Query(), ¶ms.Metadata) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "metadata", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListInstances(w, r) + siw.Handler.ListInstances(w, r, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8720,6 +8790,7 @@ func (response GetIngress500JSONResponse) VisitGetIngressResponse(w http.Respons } type ListInstancesRequestObject struct { + Params ListInstancesParams } type ListInstancesResponseObject interface { @@ -10155,9 +10226,11 @@ func (sh *strictHandler) GetIngress(w http.ResponseWriter, r *http.Request, id s } // ListInstances operation middleware -func (sh *strictHandler) ListInstances(w http.ResponseWriter, r *http.Request) { +func (sh *strictHandler) ListInstances(w http.ResponseWriter, r *http.Request, params ListInstancesParams) { var request ListInstancesRequestObject + request.Params = params + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { return sh.ssi.ListInstances(ctx, request.(ListInstancesRequestObject)) } @@ -10675,174 +10748,177 @@ func (sh *strictHandler) GetVolume(w http.ResponseWriter, r *http.Request, id st // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "dbsZl+rocHA4CD6++fi/AQAA//9Z2t3iWeoAAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/openapi.yaml b/openapi.yaml index f60727fd..af4abb38 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1294,6 +1294,26 @@ paths: operationId: listInstances security: - bearerAuth: [] + parameters: + - name: state + in: query + required: false + schema: + $ref: "#/components/schemas/InstanceState" + description: Filter instances by state (e.g., Running, Stopped) + - name: metadata + in: query + required: false + style: deepObject + explode: true + schema: + type: object + additionalProperties: + type: string + description: | + Filter instances by metadata key-value pairs. Uses deepObject style: + ?metadata[team]=backend&metadata[env]=staging + Multiple entries are ANDed together. All specified key-value pairs must match. responses: 200: description: List of instances