mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:37:23 +00:00
feat(system api): list instances by domains (#6806)
Allow to list instances by their domains on the system API. closes #6785
This commit is contained in:
parent
b9061ffadc
commit
ad26ca88d7
@ -63,6 +63,8 @@ func InstanceQueryToModel(searchQuery *instance_pb.Query) (query.SearchQuery, er
|
|||||||
switch q := searchQuery.Query.(type) {
|
switch q := searchQuery.Query.(type) {
|
||||||
case *instance_pb.Query_IdQuery:
|
case *instance_pb.Query_IdQuery:
|
||||||
return query.NewInstanceIDsListSearchQuery(q.IdQuery.Ids...)
|
return query.NewInstanceIDsListSearchQuery(q.IdQuery.Ids...)
|
||||||
|
case *instance_pb.Query_DomainQuery:
|
||||||
|
return query.NewInstanceDomainsListSearchQuery(q.DomainQuery.Domains...)
|
||||||
default:
|
default:
|
||||||
return nil, errors.ThrowInvalidArgument(nil, "INST-3m0se", "List.Query.Invalid")
|
return nil, errors.ThrowInvalidArgument(nil, "INST-3m0se", "List.Query.Invalid")
|
||||||
}
|
}
|
||||||
|
109
internal/api/grpc/system/instance_integration_test.go
Normal file
109
internal/api/grpc/system/instance_integration_test.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package system_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/instance"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/object"
|
||||||
|
system_pb "github.com/zitadel/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServer_ListInstances(t *testing.T) {
|
||||||
|
domain, instanceID, _ := Tester.UseIsolatedInstance(CTX, SystemCTX)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
req *system_pb.ListInstancesRequest
|
||||||
|
want []*instance.Instance
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty query error",
|
||||||
|
req: &system_pb.ListInstancesRequest{
|
||||||
|
Queries: []*instance.Query{{}},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-existing id",
|
||||||
|
req: &system_pb.ListInstancesRequest{
|
||||||
|
Queries: []*instance.Query{{
|
||||||
|
Query: &instance.Query_IdQuery{
|
||||||
|
IdQuery: &instance.IdsQuery{
|
||||||
|
Ids: []string{"foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: []*instance.Instance{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get 1 by id",
|
||||||
|
req: &system_pb.ListInstancesRequest{
|
||||||
|
Query: &object.ListQuery{
|
||||||
|
Limit: 1,
|
||||||
|
},
|
||||||
|
Queries: []*instance.Query{{
|
||||||
|
Query: &instance.Query_IdQuery{
|
||||||
|
IdQuery: &instance.IdsQuery{
|
||||||
|
Ids: []string{instanceID},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: []*instance.Instance{{
|
||||||
|
Id: instanceID,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-existing domain",
|
||||||
|
req: &system_pb.ListInstancesRequest{
|
||||||
|
Queries: []*instance.Query{{
|
||||||
|
Query: &instance.Query_DomainQuery{
|
||||||
|
DomainQuery: &instance.DomainsQuery{
|
||||||
|
Domains: []string{"foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: []*instance.Instance{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get 1 by domain",
|
||||||
|
req: &system_pb.ListInstancesRequest{
|
||||||
|
Query: &object.ListQuery{
|
||||||
|
Limit: 1,
|
||||||
|
},
|
||||||
|
Queries: []*instance.Query{{
|
||||||
|
Query: &instance.Query_DomainQuery{
|
||||||
|
DomainQuery: &instance.DomainsQuery{
|
||||||
|
Domains: []string{domain},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: []*instance.Instance{{
|
||||||
|
Id: instanceID,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
resp, err := Tester.Client.System.ListInstances(SystemCTX, tt.req)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
got := resp.GetResult()
|
||||||
|
assert.Len(t, got, len(tt.want))
|
||||||
|
for i := 0; i < len(tt.want); i++ {
|
||||||
|
assert.Equalf(t, tt.want[i].GetId(), got[i].GetId(), "instance[%d] id", i)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -150,6 +150,15 @@ func NewInstanceIDsListSearchQuery(ids ...string) (SearchQuery, error) {
|
|||||||
return NewListQuery(InstanceColumnID, list, ListIn)
|
return NewListQuery(InstanceColumnID, list, ListIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewInstanceDomainsListSearchQuery(domains ...string) (SearchQuery, error) {
|
||||||
|
list := make([]interface{}, len(domains))
|
||||||
|
for i, value := range domains {
|
||||||
|
list[i] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewListQuery(InstanceDomainDomainCol, list, ListIn)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *InstanceSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
func (q *InstanceSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||||
query = q.SearchRequest.toQuery(query)
|
query = q.SearchRequest.toQuery(query)
|
||||||
for _, q := range q.Queries {
|
for _, q := range q.Queries {
|
||||||
@ -280,7 +289,8 @@ func prepareInstancesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBu
|
|||||||
return sq.Select(
|
return sq.Select(
|
||||||
InstanceColumnID.identifier(),
|
InstanceColumnID.identifier(),
|
||||||
countColumn.identifier(),
|
countColumn.identifier(),
|
||||||
).From(instanceTable.identifier()),
|
).From(instanceTable.identifier()).
|
||||||
|
LeftJoin(join(InstanceDomainInstanceIDCol, InstanceColumnID)),
|
||||||
func(builder sq.SelectBuilder) sq.SelectBuilder {
|
func(builder sq.SelectBuilder) sq.SelectBuilder {
|
||||||
return sq.Select(
|
return sq.Select(
|
||||||
instanceFilterCountColumn,
|
instanceFilterCountColumn,
|
||||||
|
@ -55,7 +55,8 @@ var (
|
|||||||
` projections.instance_domains.creation_date,` +
|
` projections.instance_domains.creation_date,` +
|
||||||
` projections.instance_domains.change_date, ` +
|
` projections.instance_domains.change_date, ` +
|
||||||
` projections.instance_domains.sequence` +
|
` projections.instance_domains.sequence` +
|
||||||
` FROM (SELECT projections.instances.id, COUNT(*) OVER () FROM projections.instances) AS f` +
|
` FROM (SELECT projections.instances.id, COUNT(*) OVER () FROM projections.instances` +
|
||||||
|
` LEFT JOIN projections.instance_domains ON projections.instances.id = projections.instance_domains.instance_id) AS f` +
|
||||||
` LEFT JOIN projections.instances ON f.id = projections.instances.id` +
|
` LEFT JOIN projections.instances ON f.id = projections.instances.id` +
|
||||||
` LEFT JOIN projections.instance_domains ON f.id = projections.instance_domains.instance_id` +
|
` LEFT JOIN projections.instance_domains ON f.id = projections.instance_domains.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`
|
` AS OF SYSTEM TIME '-1 ms'`
|
||||||
|
@ -71,6 +71,7 @@ message Query {
|
|||||||
option (validate.required) = true;
|
option (validate.required) = true;
|
||||||
|
|
||||||
IdsQuery id_query = 1;
|
IdsQuery id_query = 1;
|
||||||
|
DomainsQuery domain_query = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +84,17 @@ message IdsQuery {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message DomainsQuery {
|
||||||
|
repeated string domains = 1 [
|
||||||
|
(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
max_items: 20,
|
||||||
|
example: "[\"my-instace.zitadel.cloud\", \"auth.custom.com\"]";
|
||||||
|
description: "Return the instances that have the requested domains";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
enum FieldName {
|
enum FieldName {
|
||||||
FIELD_NAME_UNSPECIFIED = 0;
|
FIELD_NAME_UNSPECIFIED = 0;
|
||||||
FIELD_NAME_ID = 1;
|
FIELD_NAME_ID = 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user