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

Tenant utils #644

Closed
wants to merge 24 commits into from
Closed

Tenant utils #644

wants to merge 24 commits into from

Conversation

nir-sopher
Copy link
Contributor

Adding the "TenantUtils" class allowing to check if resource is accessible (tenancy wise).
The class provides further tenants related functionality like get the tenants in hierarchic order, check if a tenant is a root tenant, etc.

The tenants API was adjusted to use this class as well as permit "tenant resource" operations based on the current user tenancy

Copy link
Member

@mitchell852 mitchell852 left a comment

Choose a reason for hiding this comment

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

some comments for you. seems to work as i'd expect.

while ( my $row = $rs_data->next ) {
$idnames{ $row->id } = $row->name;
}
my $tenant_utils = UI::TenantUtils->new($self);
Copy link
Member

Choose a reason for hiding this comment

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

this doesn't seem like it's in the right place. how about putting TenantUtils in the Utils directory?

Copy link
Member

Choose a reason for hiding this comment

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

and then you can just call it Utils::Tenant

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool:) Will do.
I was not aware of this dir, just put it next to the "Util.pm"....

if ( !defined( $params->{parentId}) && !$self->isRootTenant($id) ) {
my $tenant_utils = UI::TenantUtils->new($self);
my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef);

Copy link
Member

Choose a reason for hiding this comment

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

how about right here adding something like:

if ( is_root_tenant($tenants_data, $id) ) {
return $self->alert("Root tenant cannot be updated.");
}

I think we agreed that the root tenant can't be updated but I could be wrong. Anyhow, if you put this code right about here, then you won't have to check is_root_tenant() anymore in this function which I think will make your code easier to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed we agreed that a "root" tenant cannot become not root, and a non-root cannot become root. It also cannot be disabled.
Does it mean that a root tenant cannot be changed? I;m not sure but it indeed simolify things.
Will do

Copy link
Member

Choose a reason for hiding this comment

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

yes, i would say the root tenant can't be changed in any way. you can't change it's name, or it's active flag or it's parent (which has to be null). that is a record in the database that can't be changed at all thru the api.

#this is a write operation, allowed only by parents of the tenant (which are the owners of the resource of type tenant)
my $current_resource_tenancy = $self->db->resultset('Tenant')->search( { id => $id } )->get_column('parent_id')->single();
if (!defined($current_resource_tenancy)) {
#no parent - the tenant is its-own owner
Copy link
Member

Choose a reason for hiding this comment

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

every tenant must have a parent, right? except for the root tenant. therefore, I don't think this is necessary if you follow my advice above and exit the function if the tenant is the root tenant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed

return $self->alert("Failed to retrieve tenant height.");
}

if ($parent_depth+$tenant_height+1 > $tenant_utils->max_heirarchy_limit())
Copy link
Member

Choose a reason for hiding this comment

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

can we just get rid of the max_heirarchy_limit? that would get rid of your need to figure out depth and height and simplify this code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The limit is there to avoid infinite loops in tenant-utils in case of cyclic parent pointing. There is no way I;m aware of to create such loops but bugs may prove me wrong:)
As I set a limit in the loops themselves, I wanted to keep the code coherent and block the option to create deeper hierarchy.

Copy link
Member

Choose a reason for hiding this comment

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

ok, i see

Copy link
Member

Choose a reason for hiding this comment

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

so i've been thinking about this a little more. by putting in a max hierarchy depth, you are putting in a safety net in case somehow cyclical parents are created. for example.

root has no parent
foo has baz parent <-- cyclical
bar has foo parent
baz has bar parent

however, this feels pretty hacky putting in this safety net and it could cover up valid problems. i think it's more important to just ensure that the parent for a tenant can never be assigned as itself or as a child tenant and then make sure you have a robust set of tests to validate this. for example:

  • root
    -- foo
    --- bar
    ---- baz

when updating the bar tenant, bar and baz are invalid parents.

IF a bug slips thru and an infinite loop is created, then we fix it and write a test case to represent the scenario that created an infinite loop to ensure it is fixed and doesn't happen again. safety nets worry me because they may cover up bugs that need to be fixed.

Copy link
Member

Choose a reason for hiding this comment

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

inside your is_ancestor function, you probably need a recursive function to walk down the tree starting with the tenant to be updated to ensure that the new parent is != self or child.

so your function call would look like this

if (!is_ancestor($tenant, $parent)) return $self->alert("Invalid parent")

here's an article regarding recursion in perl: https://perlmaven.com/recursive-subroutines

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, safety nets may cover up bugs, but not in this case - the operation will fail instead of crashing or getting stuck. Then we can debug it.
Furthermore, we will have an error in the log pointing out the reason of the failure - what we will not have if we get into an infinite loop/recursion.

my $is_tenant_achestor_of_parent = $tenant_utils->is_anchestor_of($tenants_data, $id, $params->{parentId});
if (!defined($is_tenant_achestor_of_parent))
{
return $self->alert("Failed to check tenant and parent current relations.");
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this error message

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The above test comes to verify we do not create cyclic graph by parent pointing. We check if the designated child is already an ancestor of his parent.

return $self->alert("Failed to retrieve parent tenant depth.");
}

if ($parent_depth+1 > $tenant_utils->max_heirarchy_limit()-1)
Copy link
Member

Choose a reason for hiding this comment

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

again, if we get rid of the max_heirarchy_limit, then you can simplify this code.

my $tenant_utils = UI::TenantUtils->new($self);
my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef);

if (!$tenant_utils->is_tenant_resource_accessible($tenants_data, $parent_tenant)) {
Copy link
Member

Choose a reason for hiding this comment

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

i don't think that deleting a tenant should matter what the parent tenant is. for example, if this is the tenant hierarcy:

  • root
    -- tenant 1
    --- tenant 1a
    --- tenant 1b

and i have a user with tenant = tenant 1a, then i should be able to delete tenant 1a even though i don't have tenant 1 assigned to me. what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see the parent as an owner of the child, and as such he is the one to be able to delete it.
It is a matter of taste, but note: anyhow a user must not delete his own tenant...

Copy link
Member

Choose a reason for hiding this comment

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

oh, that's a good point. if i try to delete my own tenant, i will get back "sorry, this tenant is assigned to a user", right?

@@ -404,7 +406,7 @@ sub current {
my $self = shift;
my @data;
my $current_username = $self->current_user()->{username};

my $tenantUtils = UI::TenantUtils->new($self);
Copy link
Member

Choose a reason for hiding this comment

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

this can go away. you are not using this variable.

@nir-sopher
Copy link
Contributor Author

nir-sopher commented Jun 29, 2017 via email

@nir-sopher
Copy link
Contributor Author

file move moved as required

@asfgit asfgit closed this in d37e386 Jul 18, 2017
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