mirror of
https://github.com/grafana/grafana.git
synced 2026-02-03 20:49:50 -05:00
IAM: Improvements on the user teams endpoint (#117082)
minor changes on the user teams endpoint
This commit is contained in:
parent
57958926ab
commit
56bde41a99
8 changed files with 132 additions and 132 deletions
|
|
@ -38,8 +38,9 @@ userv0alpha1: userKind & {
|
|||
"GET": {
|
||||
response: {
|
||||
#UserTeam: {
|
||||
teamRef: v0alpha1.TeamRef
|
||||
permission: v0alpha1.TeamPermission
|
||||
user: string
|
||||
team: string
|
||||
permission: string
|
||||
external: bool
|
||||
}
|
||||
items: [...#UserTeam]
|
||||
|
|
|
|||
|
|
@ -4,37 +4,17 @@ package v0alpha1
|
|||
|
||||
// +k8s:openapi-gen=true
|
||||
type VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam struct {
|
||||
TeamRef TeamRef `json:"teamRef"`
|
||||
Permission TeamPermission `json:"permission"`
|
||||
External bool `json:"external"`
|
||||
User string `json:"user"`
|
||||
Team string `json:"team"`
|
||||
Permission string `json:"permission"`
|
||||
External bool `json:"external"`
|
||||
}
|
||||
|
||||
// NewVersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam creates a new VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam object.
|
||||
func NewVersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam() *VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam {
|
||||
return &VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam{
|
||||
TeamRef: *NewTeamRef(),
|
||||
}
|
||||
return &VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TeamRef struct {
|
||||
// Name is the unique identifier for a team.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// NewTeamRef creates a new TeamRef object.
|
||||
func NewTeamRef() *TeamRef {
|
||||
return &TeamRef{}
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type TeamPermission string
|
||||
|
||||
const (
|
||||
TeamPermissionAdmin TeamPermission = "admin"
|
||||
TeamPermissionMember TeamPermission = "member"
|
||||
)
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type GetTeamsBody struct {
|
||||
Items []VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam `json:"items"`
|
||||
|
|
|
|||
40
apps/iam/pkg/apis/iam/v0alpha1/zz_openapi_gen.go
generated
40
apps/iam/pkg/apis/iam/v0alpha1/zz_openapi_gen.go
generated
|
|
@ -76,7 +76,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamLBACRuleList": schema_pkg_apis_iam_v0alpha1_TeamLBACRuleList(ref),
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamLBACRuleSpec": schema_pkg_apis_iam_v0alpha1_TeamLBACRuleSpec(ref),
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamList": schema_pkg_apis_iam_v0alpha1_TeamList(ref),
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamRef": schema_pkg_apis_iam_v0alpha1_TeamRef(ref),
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamSpec": schema_pkg_apis_iam_v0alpha1_TeamSpec(ref),
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamStatus": schema_pkg_apis_iam_v0alpha1_TeamStatus(ref),
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamstatusOperatorState": schema_pkg_apis_iam_v0alpha1_TeamstatusOperatorState(ref),
|
||||
|
|
@ -3013,27 +3012,6 @@ func schema_pkg_apis_iam_v0alpha1_TeamList(ref common.ReferenceCallback) common.
|
|||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_iam_v0alpha1_TeamRef(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Name is the unique identifier for a team.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"name"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_iam_v0alpha1_TeamSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
|
@ -3437,10 +3415,18 @@ func schema_pkg_apis_iam_v0alpha1_VersionsV0alpha1Kinds6RoutesTeamsGETResponseUs
|
|||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"teamRef": {
|
||||
"user": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamRef"),
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"team": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"permission": {
|
||||
|
|
@ -3458,11 +3444,9 @@ func schema_pkg_apis_iam_v0alpha1_VersionsV0alpha1Kinds6RoutesTeamsGETResponseUs
|
|||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"teamRef", "permission", "external"},
|
||||
Required: []string{"user", "team", "permission", "external"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamRef"},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateUsersAPIGroup(opts builder.AP
|
|||
b.features,
|
||||
)
|
||||
|
||||
storage[userResource.StoragePath("teams")] = user.NewTeamMemberREST(teamBindingSearchClient, b.tracing, b.features)
|
||||
storage[userResource.StoragePath("teams")] = user.NewUserTeamREST(teamBindingSearchClient, b.tracing, b.features)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ type UserTeamREST struct {
|
|||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
func NewTeamMemberREST(client resourcepb.ResourceIndexClient, tracer trace.Tracer, features featuremgmt.FeatureToggles) *UserTeamREST {
|
||||
func NewUserTeamREST(client resourcepb.ResourceIndexClient, tracer trace.Tracer, features featuremgmt.FeatureToggles) *UserTeamREST {
|
||||
return &UserTeamREST{
|
||||
log: log.New("grafana-apiserver.user.teams"),
|
||||
client: client,
|
||||
|
|
@ -123,6 +123,7 @@ func (s *UserTeamREST) Connect(ctx context.Context, name string, options runtime
|
|||
Page: int64(page),
|
||||
Explain: queryParams.Has("explain") && queryParams.Get("explain") != "false",
|
||||
Fields: []string{
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_BINDING_SUBJECT_NAME,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_BINDING_TEAM_REF,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_BINDING_PERMISSION,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_BINDING_EXTERNAL,
|
||||
|
|
@ -135,7 +136,7 @@ func (s *UserTeamREST) Connect(ctx context.Context, name string, options runtime
|
|||
return
|
||||
}
|
||||
|
||||
searchResults, err := s.parseResults(result, searchRequest.Offset)
|
||||
searchResults, err := parseResults(result, searchRequest.Offset)
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
|
|
@ -158,7 +159,7 @@ func (s *UserTeamREST) ConnectMethods() []string {
|
|||
return []string{http.MethodGet}
|
||||
}
|
||||
|
||||
func (h *UserTeamREST) parseResults(result *resourcepb.ResourceSearchResponse, offset int64) (iamv0alpha1.GetTeamsBody, error) {
|
||||
func parseResults(result *resourcepb.ResourceSearchResponse, offset int64) (iamv0alpha1.GetTeamsBody, error) {
|
||||
if result == nil {
|
||||
return iamv0alpha1.GetTeamsBody{}, nil
|
||||
}
|
||||
|
|
@ -169,7 +170,8 @@ func (h *UserTeamREST) parseResults(result *resourcepb.ResourceSearchResponse, o
|
|||
return iamv0alpha1.GetTeamsBody{}, nil
|
||||
}
|
||||
|
||||
teamRefIDX := -1
|
||||
userIDX := -1
|
||||
teamIDX := -1
|
||||
permissionIDX := -1
|
||||
externalIDX := -1
|
||||
|
||||
|
|
@ -179,8 +181,10 @@ func (h *UserTeamREST) parseResults(result *resourcepb.ResourceSearchResponse, o
|
|||
}
|
||||
|
||||
switch v.Name {
|
||||
case builders.TEAM_BINDING_SUBJECT_NAME:
|
||||
userIDX = i
|
||||
case builders.TEAM_BINDING_TEAM_REF:
|
||||
teamRefIDX = i
|
||||
teamIDX = i
|
||||
case builders.TEAM_BINDING_PERMISSION:
|
||||
permissionIDX = i
|
||||
case builders.TEAM_BINDING_EXTERNAL:
|
||||
|
|
@ -188,7 +192,10 @@ func (h *UserTeamREST) parseResults(result *resourcepb.ResourceSearchResponse, o
|
|||
}
|
||||
}
|
||||
|
||||
if teamRefIDX < 0 {
|
||||
if userIDX < 0 {
|
||||
return iamv0alpha1.GetTeamsBody{}, fmt.Errorf("required column '%s' not found in search results", builders.TEAM_BINDING_SUBJECT_NAME)
|
||||
}
|
||||
if teamIDX < 0 {
|
||||
return iamv0alpha1.GetTeamsBody{}, fmt.Errorf("required column '%s' not found in search results", builders.TEAM_BINDING_TEAM_REF)
|
||||
}
|
||||
if permissionIDX < 0 {
|
||||
|
|
@ -208,8 +215,9 @@ func (h *UserTeamREST) parseResults(result *resourcepb.ResourceSearchResponse, o
|
|||
}
|
||||
|
||||
body.Items[i] = iamv0alpha1.VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam{
|
||||
TeamRef: iamv0alpha1.TeamRef{Name: string(row.Cells[teamRefIDX])},
|
||||
Permission: iamv0alpha1.TeamPermission(string(row.Cells[permissionIDX])),
|
||||
User: string(row.Cells[userIDX]),
|
||||
Team: string(row.Cells[teamIDX]),
|
||||
Permission: string(row.Cells[permissionIDX]),
|
||||
External: string(row.Cells[externalIDX]) == "true",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
iamv0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
||||
|
|
@ -41,7 +40,7 @@ func (m *mockResponder) Error(err error) {
|
|||
func TestUserTeamREST_Connect(t *testing.T) {
|
||||
t.Run("should create handler with default pagination", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -68,7 +67,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
|
||||
t.Run("should parse limit query parameter", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -89,7 +88,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
|
||||
t.Run("should parse offset query parameter and calculate page", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -112,7 +111,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
|
||||
t.Run("should parse page query parameter and calculate offset", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -135,7 +134,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
|
||||
t.Run("should parse explain query parameter", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -156,7 +155,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
|
||||
t.Run("should not enable explain when explain=false", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -177,7 +176,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
|
||||
t.Run("should return error when identity is missing", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := context.Background()
|
||||
responder := &mockResponder{}
|
||||
|
|
@ -200,7 +199,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
mockClient := &MockClient{
|
||||
MockError: errors.New("search failed"),
|
||||
}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -227,6 +226,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
{
|
||||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
{Name: "subject_name"},
|
||||
{Name: "team_ref"},
|
||||
{Name: "permission"},
|
||||
{Name: "external"},
|
||||
|
|
@ -234,6 +234,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
Rows: []*resourcepb.ResourceTableRow{
|
||||
{
|
||||
Cells: [][]byte{
|
||||
[]byte("user1"),
|
||||
[]byte("team1"),
|
||||
[]byte("admin"),
|
||||
[]byte("true"),
|
||||
|
|
@ -241,6 +242,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Cells: [][]byte{
|
||||
[]byte("user2"),
|
||||
[]byte("team2"),
|
||||
[]byte("member"),
|
||||
[]byte("false"),
|
||||
|
|
@ -251,7 +253,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -274,17 +276,19 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
err = json.Unmarshal(w.Body.Bytes(), &result)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result.Items, 2)
|
||||
require.Equal(t, "team1", result.Items[0].TeamRef.Name)
|
||||
require.Equal(t, iamv0alpha1.TeamPermissionAdmin, result.Items[0].Permission)
|
||||
require.Equal(t, "user1", result.Items[0].User)
|
||||
require.Equal(t, "team1", result.Items[0].Team)
|
||||
require.Equal(t, "admin", result.Items[0].Permission)
|
||||
require.True(t, result.Items[0].External)
|
||||
require.Equal(t, "team2", result.Items[1].TeamRef.Name)
|
||||
require.Equal(t, iamv0alpha1.TeamPermissionMember, result.Items[1].Permission)
|
||||
require.Equal(t, "user2", result.Items[1].User)
|
||||
require.Equal(t, "team2", result.Items[1].Team)
|
||||
require.Equal(t, "member", result.Items[1].Permission)
|
||||
require.False(t, result.Items[1].External)
|
||||
})
|
||||
|
||||
t.Run("should include correct fields in search request", func(t *testing.T) {
|
||||
mockClient := &MockClient{}
|
||||
handler := NewTeamMemberREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
handler := NewUserTeamREST(mockClient, tracing.NewNoopTracerService(), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
ctx := identity.WithRequester(context.Background(), &identity.StaticRequester{
|
||||
Namespace: "test-namespace",
|
||||
|
|
@ -301,6 +305,7 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
httpHandler.ServeHTTP(w, req)
|
||||
|
||||
expectedFields := []string{
|
||||
resource.SEARCH_FIELD_PREFIX + "subject_name",
|
||||
resource.SEARCH_FIELD_PREFIX + "team_ref",
|
||||
resource.SEARCH_FIELD_PREFIX + "permission",
|
||||
resource.SEARCH_FIELD_PREFIX + "external",
|
||||
|
|
@ -313,10 +318,8 @@ func TestUserTeamREST_Connect(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUserTeamREST_parseResults(t *testing.T) {
|
||||
handler := NewTeamMemberREST(nil, noop.NewTracerProvider().Tracer("test"), featuremgmt.WithFeatures(featuremgmt.FlagKubernetesTeamBindings))
|
||||
|
||||
t.Run("should return empty body when result is nil", func(t *testing.T) {
|
||||
result, err := handler.parseResults(nil, 0)
|
||||
result, err := parseResults(nil, 0)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, result.Items)
|
||||
})
|
||||
|
|
@ -331,7 +334,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.Error(t, err)
|
||||
require.Empty(t, result.Items)
|
||||
require.Contains(t, err.Error(), "500 error searching")
|
||||
|
|
@ -342,7 +345,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
searchResult := &resourcepb.ResourceSearchResponse{
|
||||
Results: nil,
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, result.Items)
|
||||
})
|
||||
|
|
@ -351,13 +354,14 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
searchResult := &resourcepb.ResourceSearchResponse{
|
||||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
{Name: "subject_name"},
|
||||
{Name: "permission"},
|
||||
{Name: "external"},
|
||||
},
|
||||
Rows: []*resourcepb.ResourceTableRow{},
|
||||
},
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "required column 'team_ref' not found")
|
||||
require.Empty(t, result.Items)
|
||||
|
|
@ -367,13 +371,14 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
searchResult := &resourcepb.ResourceSearchResponse{
|
||||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
{Name: "subject_name"},
|
||||
{Name: "team_ref"},
|
||||
{Name: "external"},
|
||||
},
|
||||
Rows: []*resourcepb.ResourceTableRow{},
|
||||
},
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "required column 'permission' not found")
|
||||
require.Empty(t, result.Items)
|
||||
|
|
@ -383,19 +388,20 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
searchResult := &resourcepb.ResourceSearchResponse{
|
||||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
{Name: "subject_name"},
|
||||
{Name: "team_ref"},
|
||||
{Name: "permission"},
|
||||
},
|
||||
Rows: []*resourcepb.ResourceTableRow{},
|
||||
},
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "required column 'external' not found")
|
||||
require.Empty(t, result.Items)
|
||||
})
|
||||
|
||||
t.Run("should parse valid results correctly", func(t *testing.T) {
|
||||
t.Run("should return error when subject_name column is missing", func(t *testing.T) {
|
||||
searchResult := &resourcepb.ResourceSearchResponse{
|
||||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
|
|
@ -403,9 +409,27 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
{Name: "permission"},
|
||||
{Name: "external"},
|
||||
},
|
||||
},
|
||||
}
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "required column 'subject_name' not found")
|
||||
require.Empty(t, result.Items)
|
||||
})
|
||||
|
||||
t.Run("should parse valid results correctly", func(t *testing.T) {
|
||||
searchResult := &resourcepb.ResourceSearchResponse{
|
||||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
{Name: "subject_name"},
|
||||
{Name: "team_ref"},
|
||||
{Name: "permission"},
|
||||
{Name: "external"},
|
||||
},
|
||||
Rows: []*resourcepb.ResourceTableRow{
|
||||
{
|
||||
Cells: [][]byte{
|
||||
[]byte("user1"),
|
||||
[]byte("team1"),
|
||||
[]byte("admin"),
|
||||
[]byte("true"),
|
||||
|
|
@ -413,6 +437,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Cells: [][]byte{
|
||||
[]byte("user2"),
|
||||
[]byte("team2"),
|
||||
[]byte("member"),
|
||||
[]byte("false"),
|
||||
|
|
@ -421,16 +446,18 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result.Items, 2)
|
||||
|
||||
require.Equal(t, "team1", result.Items[0].TeamRef.Name)
|
||||
require.Equal(t, iamv0alpha1.TeamPermissionAdmin, result.Items[0].Permission)
|
||||
require.Equal(t, "user1", result.Items[0].User)
|
||||
require.Equal(t, "team1", result.Items[0].Team)
|
||||
require.Equal(t, "admin", result.Items[0].Permission)
|
||||
require.True(t, result.Items[0].External)
|
||||
|
||||
require.Equal(t, "team2", result.Items[1].TeamRef.Name)
|
||||
require.Equal(t, iamv0alpha1.TeamPermissionMember, result.Items[1].Permission)
|
||||
require.Equal(t, "user2", result.Items[1].User)
|
||||
require.Equal(t, "team2", result.Items[1].Team)
|
||||
require.Equal(t, "member", result.Items[1].Permission)
|
||||
require.False(t, result.Items[1].External)
|
||||
})
|
||||
|
||||
|
|
@ -438,6 +465,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
searchResult := &resourcepb.ResourceSearchResponse{
|
||||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
{Name: "subject_name"},
|
||||
{Name: "team_ref"},
|
||||
{Name: "permission"},
|
||||
{Name: "external"},
|
||||
|
|
@ -445,6 +473,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
Rows: []*resourcepb.ResourceTableRow{
|
||||
{
|
||||
Cells: [][]byte{
|
||||
[]byte("user1"),
|
||||
[]byte("team1"),
|
||||
[]byte("admin"),
|
||||
// Missing external cell
|
||||
|
|
@ -453,7 +482,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "mismatch number of columns and cells")
|
||||
require.Empty(t, result.Items)
|
||||
|
|
@ -464,6 +493,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
Results: &resourcepb.ResourceTable{
|
||||
Columns: []*resourcepb.ResourceTableColumnDefinition{
|
||||
nil,
|
||||
{Name: "subject_name"},
|
||||
{Name: "team_ref"},
|
||||
{Name: "permission"},
|
||||
{Name: "external"},
|
||||
|
|
@ -472,6 +502,7 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
{
|
||||
Cells: [][]byte{
|
||||
[]byte(""),
|
||||
[]byte("user1"),
|
||||
[]byte("team1"),
|
||||
[]byte("admin"),
|
||||
[]byte("true"),
|
||||
|
|
@ -480,9 +511,12 @@ func TestUserTeamREST_parseResults(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
result, err := handler.parseResults(searchResult, 0)
|
||||
result, err := parseResults(searchResult, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result.Items, 1)
|
||||
require.Equal(t, "team1", result.Items[0].TeamRef.Name)
|
||||
require.Equal(t, "user1", result.Items[0].User)
|
||||
require.Equal(t, "team1", result.Items[0].Team)
|
||||
require.Equal(t, "admin", result.Items[0].Permission)
|
||||
require.True(t, result.Items[0].External)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@ import (
|
|||
|
||||
type userTeamsResponse struct {
|
||||
Items []struct {
|
||||
TeamRef struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"teamRef"`
|
||||
Team string `json:"team"`
|
||||
User string `json:"user"`
|
||||
Permission string `json:"permission"`
|
||||
External bool `json:"external"`
|
||||
} `json:"items"`
|
||||
|
|
@ -60,12 +59,12 @@ func TestIntegrationUserTeams(t *testing.T) {
|
|||
|
||||
t.Cleanup(func() { helper.Shutdown() })
|
||||
|
||||
doUserTeamsTests(t, helper, mode)
|
||||
doUserTeamsTests(t, helper)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func doUserTeamsTests(t *testing.T, helper *apis.K8sTestHelper, mode rest.DualWriterMode) {
|
||||
func doUserTeamsTests(t *testing.T, helper *apis.K8sTestHelper) {
|
||||
ctx := context.Background()
|
||||
orgNS := helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID())
|
||||
|
||||
|
|
@ -123,7 +122,7 @@ func doUserTeamsTests(t *testing.T, helper *apis.K8sTestHelper, mode rest.DualWr
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("returns the bound team for the user with dual writer mode %d", mode), func(t *testing.T) {
|
||||
t.Run("returns the bound team for the user", func(t *testing.T) {
|
||||
path := fmt.Sprintf("/apis/iam.grafana.app/v0alpha1/namespaces/default/users/%s/teams", u1.GetName())
|
||||
|
||||
var res userTeamsResponse
|
||||
|
|
@ -137,11 +136,13 @@ func doUserTeamsTests(t *testing.T, helper *apis.K8sTestHelper, mode rest.DualWr
|
|||
require.True(t, containsTeam(res, teams[0].GetName()), "expected response to contain team %q, got %#v", teams[0].GetName(), res.Items)
|
||||
|
||||
item := findTeam(res, teams[0].GetName())
|
||||
require.Equal(t, u1.GetName(), item.User)
|
||||
require.Equal(t, teams[0].GetName(), item.Team)
|
||||
require.Equal(t, "admin", item.Permission)
|
||||
require.False(t, item.External)
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("does not return the bound team for a different user with dual writer mode %d", mode), func(t *testing.T) {
|
||||
t.Run("does not return the bound team for a different user", func(t *testing.T) {
|
||||
path := fmt.Sprintf("/apis/iam.grafana.app/v0alpha1/namespaces/default/users/%s/teams", u2.GetName())
|
||||
|
||||
var res userTeamsResponse
|
||||
|
|
@ -155,7 +156,7 @@ func doUserTeamsTests(t *testing.T, helper *apis.K8sTestHelper, mode rest.DualWr
|
|||
require.False(t, containsTeam(res, teams[0].GetName()), "did not expect response to contain team %q, got %#v", teams[0].GetName(), res.Items)
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("paging with page and limit with dual writer mode %d", mode), func(t *testing.T) {
|
||||
t.Run("paging with page and limit", func(t *testing.T) {
|
||||
// Page 1, Limit 2
|
||||
res1 := getUserTeamsWithPaging(t, helper, u1.GetName(), 1, 2)
|
||||
require.Len(t, res1.Items, 2)
|
||||
|
|
@ -170,24 +171,24 @@ func doUserTeamsTests(t *testing.T, helper *apis.K8sTestHelper, mode rest.DualWr
|
|||
|
||||
seen := make(map[string]bool)
|
||||
for _, item := range res1.Items {
|
||||
teamName := item.TeamRef.Name
|
||||
teamName := item.Team
|
||||
require.False(t, seen[teamName], "Team %s seen in page 1 twice", teamName)
|
||||
seen[teamName] = true
|
||||
}
|
||||
for _, item := range res2.Items {
|
||||
teamName := item.TeamRef.Name
|
||||
teamName := item.Team
|
||||
require.False(t, seen[teamName], "Team %s seen in page 1 and 2", teamName)
|
||||
seen[teamName] = true
|
||||
}
|
||||
for _, item := range res3.Items {
|
||||
teamName := item.TeamRef.Name
|
||||
teamName := item.Team
|
||||
require.False(t, seen[teamName], "Team %s seen in previous pages", teamName)
|
||||
seen[teamName] = true
|
||||
}
|
||||
require.Len(t, seen, 5, "Should have seen all 5 teams across pages")
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("paging with offset and limit with dual writer mode %d", mode), func(t *testing.T) {
|
||||
t.Run("paging with offset and limit", func(t *testing.T) {
|
||||
// Offset 0, Limit 2
|
||||
res1 := getUserTeamsWithOffset(t, helper, u1.GetName(), 0, 2)
|
||||
require.Len(t, res1.Items, 2)
|
||||
|
|
@ -202,17 +203,17 @@ func doUserTeamsTests(t *testing.T, helper *apis.K8sTestHelper, mode rest.DualWr
|
|||
|
||||
seen := make(map[string]bool)
|
||||
for _, item := range res1.Items {
|
||||
teamName := item.TeamRef.Name
|
||||
teamName := item.Team
|
||||
require.False(t, seen[teamName], "Team %s seen in offset 0 twice", teamName)
|
||||
seen[teamName] = true
|
||||
}
|
||||
for _, item := range res2.Items {
|
||||
teamName := item.TeamRef.Name
|
||||
teamName := item.Team
|
||||
require.False(t, seen[teamName], "Team %s seen in offset 0 and 2", teamName)
|
||||
seen[teamName] = true
|
||||
}
|
||||
for _, item := range res3.Items {
|
||||
teamName := item.TeamRef.Name
|
||||
teamName := item.Team
|
||||
require.False(t, seen[teamName], "Team %s seen in previous offsets", teamName)
|
||||
seen[teamName] = true
|
||||
}
|
||||
|
|
@ -231,7 +232,7 @@ func createTeamObject(helper *apis.K8sTestHelper, teamName string, title string,
|
|||
|
||||
func containsTeam(res userTeamsResponse, teamName string) bool {
|
||||
for _, it := range res.Items {
|
||||
if it.TeamRef.Name == teamName {
|
||||
if it.Team == teamName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -239,14 +240,13 @@ func containsTeam(res userTeamsResponse, teamName string) bool {
|
|||
}
|
||||
|
||||
func findTeam(res userTeamsResponse, teamName string) (out struct {
|
||||
TeamRef struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"teamRef"`
|
||||
Team string `json:"team"`
|
||||
User string `json:"user"`
|
||||
Permission string `json:"permission"`
|
||||
External bool `json:"external"`
|
||||
}) {
|
||||
for _, it := range res.Items {
|
||||
if it.TeamRef.Name == teamName {
|
||||
if it.Team == teamName {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7741,19 +7741,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamRef": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Name is the unique identifier for a team.",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.TeamSpec": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -8001,7 +7988,8 @@
|
|||
"github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1.VersionsV0alpha1Kinds6RoutesTeamsGETResponseUserTeam": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"teamRef",
|
||||
"user",
|
||||
"team",
|
||||
"permission",
|
||||
"external"
|
||||
],
|
||||
|
|
@ -8014,8 +8002,13 @@
|
|||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"teamRef": {
|
||||
"default": {}
|
||||
"team": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue