IAM: Implement the delete method for team bindings (#112844)
* implement the delete method for team bindings * add integration test * remove team binding search from legacy store
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
DELETE FROM {{ .Ident .TeamMemberTable }}
|
||||
WHERE uid = {{ .Arg .Command.UID }}
|
||||
@@ -38,6 +38,7 @@ type LegacyIdentityStore interface {
|
||||
ListTeamBindings(ctx context.Context, ns claims.NamespaceInfo, query ListTeamBindingsQuery) (*ListTeamBindingsResult, error)
|
||||
ListTeamMembers(ctx context.Context, ns claims.NamespaceInfo, query ListTeamMembersQuery) (*ListTeamMembersResult, error)
|
||||
UpdateTeamMember(ctx context.Context, ns claims.NamespaceInfo, cmd UpdateTeamMemberCommand) (*UpdateTeamMemberResult, error)
|
||||
DeleteTeamMember(ctx context.Context, ns claims.NamespaceInfo, cmd DeleteTeamMemberCommand) error
|
||||
}
|
||||
|
||||
var _ LegacyIdentityStore = (*legacySQLStore)(nil)
|
||||
|
||||
@@ -97,6 +97,12 @@ func TestIdentityQueries(t *testing.T) {
|
||||
return &v
|
||||
}
|
||||
|
||||
deleteTeamMember := func(q *DeleteTeamMemberCommand) sqltemplate.SQLTemplate {
|
||||
v := newDeleteTeamMember(nodb, q)
|
||||
v.SQLTemplate = mocks.NewTestingSQLTemplate()
|
||||
return &v
|
||||
}
|
||||
|
||||
deleteTeam := func(q *DeleteTeamCommand) sqltemplate.SQLTemplate {
|
||||
v := newDeleteTeam(nodb, q)
|
||||
v.SQLTemplate = mocks.NewTestingSQLTemplate()
|
||||
@@ -294,6 +300,14 @@ func TestIdentityQueries(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
sqlDeleteTeamMemberQuery: {
|
||||
{
|
||||
Name: "delete_team_member_basic",
|
||||
Data: deleteTeamMember(&DeleteTeamMemberCommand{
|
||||
UID: "team-member-1",
|
||||
}),
|
||||
},
|
||||
},
|
||||
sqlQueryUserTeamsTemplate: {
|
||||
{
|
||||
Name: "team_1_members_page_1",
|
||||
|
||||
@@ -368,6 +368,61 @@ func (s *legacySQLStore) UpdateTeamMember(ctx context.Context, ns claims.Namespa
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
type DeleteTeamMemberCommand struct {
|
||||
UID string
|
||||
}
|
||||
|
||||
var sqlDeleteTeamMemberQuery = mustTemplate("delete_team_member_query.sql")
|
||||
|
||||
func newDeleteTeamMember(sql *legacysql.LegacyDatabaseHelper, cmd *DeleteTeamMemberCommand) deleteTeamMemberQuery {
|
||||
return deleteTeamMemberQuery{
|
||||
SQLTemplate: sqltemplate.New(sql.DialectForDriver()),
|
||||
TeamMemberTable: sql.Table("team_member"),
|
||||
Command: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
type deleteTeamMemberQuery struct {
|
||||
sqltemplate.SQLTemplate
|
||||
TeamMemberTable string
|
||||
Command *DeleteTeamMemberCommand
|
||||
}
|
||||
|
||||
func (r deleteTeamMemberQuery) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *legacySQLStore) DeleteTeamMember(ctx context.Context, ns claims.NamespaceInfo, cmd DeleteTeamMemberCommand) error {
|
||||
sql, err := s.sql(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := newDeleteTeamMember(sql, &cmd)
|
||||
if err := req.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sql.DB.GetSqlxSession().WithTransaction(ctx, func(st *session.SessionTx) error {
|
||||
teamMemberQuery, err := sqltemplate.Execute(sqlDeleteTeamMemberQuery, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute team member template %q: %w", sqlDeleteTeamMemberQuery.Name(), err)
|
||||
}
|
||||
|
||||
_, err = st.Exec(ctx, teamMemberQuery, req.GetArgs()...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete team member: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanMember(rows *sql.Rows) (TeamMember, error) {
|
||||
m := TeamMember{}
|
||||
err := rows.Scan(&m.ID, &m.UID, &m.TeamUID, &m.TeamID, &m.UserUID, &m.UserID, &m.Name, &m.Email, &m.Username, &m.External, &m.Created, &m.Updated, &m.Permission)
|
||||
|
||||
Vendored
Executable
+2
@@ -0,0 +1,2 @@
|
||||
DELETE FROM `grafana`.`team_member`
|
||||
WHERE uid = 'team-member-1'
|
||||
Vendored
Executable
+2
@@ -0,0 +1,2 @@
|
||||
DELETE FROM "grafana"."team_member"
|
||||
WHERE uid = 'team-member-1'
|
||||
Vendored
Executable
+2
@@ -0,0 +1,2 @@
|
||||
DELETE FROM "grafana"."team_member"
|
||||
WHERE uid = 'team-member-1'
|
||||
@@ -125,7 +125,34 @@ func (l *LegacyBindingStore) Update(ctx context.Context, name string, objInfo re
|
||||
}
|
||||
|
||||
func (l *LegacyBindingStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
|
||||
return nil, false, apierrors.NewMethodNotSupported(bindingResource.GroupResource(), "delete")
|
||||
if !l.enableAuthnMutation {
|
||||
return nil, false, apierrors.NewMethodNotSupported(bindingResource.GroupResource(), "delete")
|
||||
}
|
||||
|
||||
ns, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// Check if the team binding exists
|
||||
_, err = l.Get(ctx, name, nil)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
err = l.store.DeleteTeamMember(ctx, ns, legacy.DeleteTeamMemberCommand{
|
||||
UID: name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return &iamv0alpha1.TeamBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: ns.Value,
|
||||
},
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
func (l *LegacyBindingStore) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *internalversion.ListOptions) (runtime.Object, error) {
|
||||
|
||||
@@ -74,7 +74,7 @@ func TestIntegrationTeamBindings(t *testing.T) {
|
||||
}
|
||||
|
||||
func doTeamBindingCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHelper, team *unstructured.Unstructured, user *unstructured.Unstructured) {
|
||||
t.Run("should create/update/get team binding using the new APIs", func(t *testing.T) {
|
||||
t.Run("should create/update/get/delete team binding using the new APIs", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
teamBindingClient := helper.GetResourceClient(apis.ResourceClientArgs{
|
||||
@@ -137,6 +137,18 @@ func doTeamBindingCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHel
|
||||
require.Equal(t, "member", fetchedSpec["permission"])
|
||||
require.Equal(t, false, fetchedSpec["external"])
|
||||
require.Equal(t, createdUID, fetched.GetName())
|
||||
|
||||
// Delete the team binding
|
||||
err = teamBindingClient.Resource.Delete(ctx, createdUID, metav1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the team binding is deleted
|
||||
_, err = teamBindingClient.Resource.Get(ctx, createdUID, metav1.GetOptions{})
|
||||
require.Error(t, err)
|
||||
var statusErr *errors.StatusError
|
||||
require.ErrorAs(t, err, &statusErr)
|
||||
require.Equal(t, int32(404), statusErr.ErrStatus.Code)
|
||||
require.Contains(t, statusErr.ErrStatus.Message, "not found")
|
||||
})
|
||||
|
||||
t.Run("should not be able to create team binding when using a user with insufficient permissions", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user