New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug 1906898: Missing User RoleBindings in the Project Access Web UI #7488
Bug 1906898: Missing User RoleBindings in the Project Access Web UI #7488
Conversation
/kind bug |
@debsmita1: This pull request references Bugzilla bug 1906898, which is valid. The bug has been moved to the POST state. 3 validation(s) were run on this bug
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
const users: UserRoleBinding[] = user.subjects?.reduce((acc, obj) => { | ||
acc.push({ | ||
roleBindingName: user.metadata.name, | ||
user: obj.name, | ||
role: user.roleRef.name, | ||
}); | ||
return acc; | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a map function? :)
}, | ||
], | ||
]), | ||
(user: RoleBinding) => (userRoleBindings = [...userRoleBindings, ...getUsersFromSubject(user)]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its similar to before, but the result of a map function should be used, otherwise can we switch to a .forEach here? Isn't this similar to this code?
export const getUserRoleBindings = (roleBindings: RoleBinding[]) => {
const userRoleBindings: UserRoleBinding[] = [];
roleBindings.forEach(
(user: RoleBinding) => userRoleBindings.push(...getUsersFromSubject(user)),
);
return userRoleBindings;
};
(untested code). Wdyt? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
used _.flatten
here
added the test for this util in project-access-form-utils.spec.ts
let groupedRole: RoleBinding; | ||
_.forEach(roleBindings, (roleBinding: RoleBinding) => { | ||
if (roleBinding.metadata.name === role.roleBindingName && roleBinding.subjects.length > 1) { | ||
_.remove(roleBinding.subjects, (subject) => subject.name === role.user); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, not a big fan of changing input parameters in a 'get' helper function. Esp. in this case where getGroupedRole
was called with some props
we should avoid this.
Did you see an option that this method return new values instead of modifying the input variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed it
import { filterRoleBindings, getUserRoleBindings } from '../project-access-form-utils'; | ||
import { Roles } from '../project-access-form-utils-types'; | ||
import { | ||
roleBindingsResourceData, | ||
roleBindingsWithRequiredRolesResult, | ||
roleBindingsWithRequiredRoles, | ||
roleBindingsWithRequiredAttributes, | ||
} from './project-access-form-data'; | ||
|
||
describe('Fetch required roles', () => { | ||
it('should fetch the only the required rolebindings', async () => { | ||
const filteredRoleBindings = filterRoleBindings(roleBindingsResourceData, Roles); | ||
expect(filteredRoleBindings).toEqual(roleBindingsWithRequiredRolesResult); | ||
}); | ||
|
||
it('should consider only the required attributes', async () => { | ||
const userRoleBindings = getUserRoleBindings(roleBindingsWithRequiredRoles); | ||
expect(userRoleBindings).toEqual(roleBindingsWithRequiredAttributes); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why remove this unit tests? The util functions still exist and are not changed, or? So I expect this tests would still run fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Changed the file name to project-access-form-utils.spec.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@debsmita1 Happy new year and sorry for the late review here. I tested the PR locally and it looks like that everything works fine for the user and I like all these new types 👍
I added some small opinionated ideas and questions. Let me know what your opinion on that points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(just changed review status)
@@ -73,3 +76,14 @@ export const sendRoleBindingRequest = (verb: string, roles: UserRoleBinding[], r | |||
}); | |||
return finalArray; | |||
}; | |||
|
|||
export const getGroupedRole = (role: UserRoleBinding, roleBindings: RoleBinding[]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your get method is mutating roleBindings
. This is not an expected side-effect of get methods.
Also, as discussed before, please make use of filter
s and find
s instead of custom running your own forEach
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
used find & filter
const users: UserRoleBinding[] = user.subjects?.reduce((acc, obj) => { | ||
acc.push({ | ||
roleBindingName: user.metadata.name, | ||
user: obj.name, | ||
role: user.roleRef.name, | ||
}); | ||
return acc; | ||
}, []); | ||
|
||
return users; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A .reduce
into an array .push
is just a .map
.
const users: UserRoleBinding[] = user.subjects?.reduce((acc, obj) => { | |
acc.push({ | |
roleBindingName: user.metadata.name, | |
user: obj.name, | |
role: user.roleRef.name, | |
}); | |
return acc; | |
}, []); | |
return users; | |
return user.subjects?.map((obj) => ({ | |
roleBindingName: user.metadata.name, | |
user: obj.name, | |
role: user.roleRef.name, | |
})); |
return users; | ||
}; | ||
|
||
export const getUserRoleBindings = (roleBindings: RoleBinding[]) => { | ||
let userRoleBindings: UserRoleBinding[] = []; | ||
roleBindings.map( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the record (I know this is old code) but .map
should always have its response used. Ideally .map
has no side-effects if possible.
}; | ||
|
||
export const getUserRoleBindings = (roleBindings) => { | ||
export const getUsersFromSubject = (user: RoleBinding) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Helps to declare what your returns will be when you're mutating and shifting values around. When it's a straight filter or find, and your input type is your output type, it's less of a concern.
In this case you're taking a RoleBinding and creating UserRoleBinding[]. Makes it easier to consume the method without having to read the method.
export const getUsersFromSubject = (user: RoleBinding) => { | |
export const getUsersFromSubject = (user: RoleBinding): UserRoleBinding[] => { |
}, | ||
], | ||
]), | ||
(user: RoleBinding) => (userRoleBindings = [...userRoleBindings, ...getUsersFromSubject(user)]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(user: RoleBinding) => (userRoleBindings = [...userRoleBindings, ...getUsersFromSubject(user)]), | |
return roleBindings.map((user) => getUsersFromSubject(user)).flat(); |
Two major things here:
- Don't assign in a return statement (we should probably get a linter to stop this)
- Avoid mutations in the middle of
.map
function calls (the purer they are the better they are)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I could have used flat
here to concatenate the sub-array elements. Thanks!
let groupedRole: RoleBinding; | ||
_.forEach(roleBindings, (roleBinding: RoleBinding) => { | ||
if (roleBinding.metadata.name === role.roleBindingName && roleBinding.subjects.length > 1) { | ||
_.remove(roleBinding.subjects, (subject) => subject.name === role.user); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason you need to remove the matching subject?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewballantyne What I am trying to do here is, if I update the role of a user(suppose A) that belongs to grouped subjects(subjects: A, B) then I am removing that user(A) from the group and sending a patch request to update the rolebinding with the user B.
2aa7c88
to
b9eeb61
Compare
b9eeb61
to
5fb9f99
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: andrewballantyne, debsmita1 The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@debsmita1: The following test failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/retest Please review the full test history for this PR and help us cut down flakes. |
@debsmita1: This pull request references Bugzilla bug 1906898, which is valid. 3 validation(s) were run on this bug
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
@debsmita1: All pull requests linked via external trackers have merged: Bugzilla bug 1906898 has been moved to the MODIFIED state. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/cherry-pick release-4.6 |
@debsmita1: new pull request created: #8034 In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Fixes:
https://issues.redhat.com/browse/ODC-4989
Closes #6836
Analysis / Root cause:
The User info is added in the
subjects
property of the RoleBinding CR. Thissubjects
is of type array and can have multiple users assigned the same role. So, previously while fetching the users from all the Role Bindings only the first element ofsubjects
was being readSolution Description:
Screen shots / Gifs for design review:
Unit test coverage report:
Added new tests
Test setup:
NA
Browser conformance: