Skip to content
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

Support swapping default roles #2868

Merged
merged 4 commits into from Feb 20, 2022
Merged

Conversation

mithmatt
Copy link
Collaborator

@mithmatt mithmatt commented Feb 20, 2022

Pseudocode:

A. patchRole(role1, default=True):
B.   set role1.default = True
     for all users:
       add role1 to user.roles
C.   for role in roles if role != role1:
       set role.default = False
       for all users:
         delete role from user.roles

This logic ensures that changeDescription for the role(s) and user(s) are updated correctly.

Alternative considered:
Directly updating relationships with bulk sqlbatch update in entity_relationship between user and role to achieve the above.
However, this does not capture change description correctly.

Describe your changes :

See #2460

Type of change :

  • Bug fix
  • Improvement
  • New feature
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation

Frontend Preview (Screenshots) :

For frontend related change, please link screenshots of your changes preview! Optional for backend related changes.

Checklist:

  • I have read the CONTRIBUTING document.
  • I have performed a self-review of my own.
  • I have tagged my reviewers below.
  • I have commented on my code, particularly in hard-to-understand areas.
  • My changes generate no new warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • All new and existing tests passed.

Reviewers

@mithmatt mithmatt marked this pull request as draft February 20, 2022 00:25
@github-actions
Copy link

The Java checkstyle failed.

Please run mvn googleformatter:format@reformat-sources in the root of your repository and commit the changes to this PR.
You can also use pre-commit to automate the Java code formatting.

You can install the pre-commit hooks with make install_test precommit_install.

@github-actions
Copy link

The Java checkstyle failed.

Please run mvn googleformatter:format@reformat-sources in the root of your repository and commit the changes to this PR.
You can also use pre-commit to automate the Java code formatting.

You can install the pre-commit hooks with make install_test precommit_install.

@mithmatt mithmatt force-pushed the default_role_swap branch 2 times, most recently from cf90559 to 286fde3 Compare February 20, 2022 04:44
@github-actions
Copy link

The Java checkstyle failed.

Please run mvn googleformatter:format@reformat-sources in the root of your repository and commit the changes to this PR.
You can also use pre-commit to automate the Java code formatting.

You can install the pre-commit hooks with make install_test precommit_install.

@@ -56,11 +59,47 @@ public RoleResourceTest() {
}

@Test
void get_queryDefaultRole(TestInfo test) throws IOException {
Role defaultRole = createRolesAndSetDefault(test, 7);
void defaultRole(TestInfo test) throws IOException {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main test for this feature

@@ -2,5 +2,6 @@
"name": "DataConsumer",
"displayName": "Data Consumer",
"description": "Users with Data Consumer role use different data assets for their day to day work.",
"deleted": false
"deleted": false,
"default": true
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting DataConsumer as default role.

}
EntityRepository<User> userRepository = Entity.getEntityRepository(Entity.USER);
users
.parallelStream()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parallelization to minimize performance impact.

Switching a default role for 100 users takes ~2 seconds on Mattbook Pro

Considered bulk update of relationships in entity_relationship table.
However, this does not capture the change description for the role update for each of the users.

Optimizing for correctness instead of performance for this feature.

try {
return withHref(uriInfo, setFields(JsonUtils.readValue(json, Role.class), fields));
} catch (IOException e) {
LOG.warn("Could not parse Role from json {}", json);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't happy about hiding this exception.
Replacing the lambda here with simple for loop.

@@ -908,12 +908,12 @@ public EntityUpdater(T original, T updated, Operation operation) {
this.operation = operation;
}

public final void update() throws IOException {
public final void update() throws IOException, ParseException {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May need to make it throws Exception in the future.
Going with this for now.


UPDATE role_entity
SET json = JSON_SET(json, '$.default', FALSE);

UPDATE role_entity
SET json = JSON_SET(json, '$.default', TRUE)
WHERE name = 'DataConsumer';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set DataConsumer as default for migration purpose.

mithmatt and others added 3 commits February 20, 2022 10:39
Pseudocode:

```
A. patchRole(role1, default=True):
B.   set role1.default = True
     for all users:
       add role1 to user.roles
C.   for role in roles if role != role1:
       set role.default = False
       for all users:
         delete role from user.roles
```

This ensures that changeDescription for the role(s) and user(s) are updated accordingly.

Potential optimization:
Adding role1 and removing role from user.roles could be considered/implemented as one change.
However, increases code complexity.
List<Role> roles = new ArrayList<>();
for (String roleJson : daoCollection.roleDAO().getDefaultRoles()) {
roles.add(withHref(uriInfo, setFields(JsonUtils.readValue(roleJson, Role.class), fields)));
}
if (roles.size() > 1) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we avoid this ever happening when the admin tries to set the default role?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, this PR with DB Transaction while swapping default role prevents getting into a situation where we have multiple default roles.

My testing pattern has been the following:

  • Start up OM with DataConsumer as default role
  • Set another role R as default role and observe that DataConsumer is no longer default and user relationships have been updated.
  • Set DataConsumer as default role and obseve that R is no longer default and user relationships have been updated.

I did a few iterations of these locally with PostMan and ended up converting the logic into a test (RoleResourceTest.defaultRole)

I left the log line as is for detection purpose, in case there are any unforeseeable edge cases being missed out (as the code evolves).

setDefaultToFalse(updatedRole);
}
recordChange("default", origRole.getDefault(), updatedRole.getDefault());
LOG.info(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets mark this as debug?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

// - the previous default role is no longer set as default
// - all users have roles set correctly (only current default role should exist)
for (int i = 0; i < 2; i++) { // Run two iterations for this test.
Role defaultRole = createRolesAndSetDefault(test, 7, i * 10);
Copy link
Collaborator Author

@mithmatt mithmatt Feb 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This creates a set of 7 arbitrary roles and chooses one at random to be default (code below)

List<Role> defaultRoles = getDefaultRoles(null, ROLE_PATCH_FIELDS);
EntityRepository<Role> roleRepository = Entity.getEntityRepository(Entity.ROLE);
// Set default=FALSE for all existing default roles.
for (Role defaultRole : defaultRoles) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will be only one default role here (at any given point of time) based on how this feature has been implemented.

continue;
}
Role origDefaultRole = roleRepository.get(null, defaultRole.getId().toString(), ROLE_PATCH_FIELDS);
Role updatedDefaultRole = roleRepository.get(null, defaultRole.getId().toString(), ROLE_PATCH_FIELDS);
Copy link
Collaborator Author

@mithmatt mithmatt Feb 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where jsonschema2pojo deep cloning would have helped.

        Role origDefaultRole = roleRepository.get(null, defaultRole.getId().toString(), ROLE_PATCH_FIELDS);
        Role updatedDefaultRole = origDefaultRole.clone();

joelittlejohn/jsonschema2pojo#230

Resorting to two db calls for now. Need to add an internal utility for cloning entities, or contribute to jsonschema2pojo

@sonarcloud
Copy link

sonarcloud bot commented Feb 20, 2022

[open-metadata-ingestion] Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@sonarcloud
Copy link

sonarcloud bot commented Feb 20, 2022

[catalog] Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 2 Code Smells

88.1% 88.1% Coverage
0.0% 0.0% Duplication

@mithmatt mithmatt merged commit 9e4d8d7 into open-metadata:main Feb 20, 2022
@mithmatt mithmatt deleted the default_role_swap branch February 20, 2022 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants