Tenant utils - documentations and changes
Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/c8d60294 Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/c8d60294 Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/c8d60294 Branch: refs/heads/master Commit: c8d602948866b3b9a79f157bb85c86eb971a6ddf Parents: 584f708 Author: nir-sopher <nirsop...@gmail.com> Authored: Mon Jun 5 03:24:05 2017 +0300 Committer: Jeremy Mitchell <mitchell...@gmail.com> Committed: Tue Jul 18 12:12:32 2017 -0600 ---------------------------------------------------------------------- traffic_ops/app/lib/API/Tenant.pm | 20 +++---- traffic_ops/app/lib/UI/TenantUtils.pm | 88 ++++++++++++++++++++++-------- traffic_ops/app/t/api/1.2/tenant.t | 76 +++++++++++++------------- 3 files changed, 113 insertions(+), 71 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c8d60294/traffic_ops/app/lib/API/Tenant.pm ---------------------------------------------------------------------- diff --git a/traffic_ops/app/lib/API/Tenant.pm b/traffic_ops/app/lib/API/Tenant.pm index ab81728..390b1e5 100644 --- a/traffic_ops/app/lib/API/Tenant.pm +++ b/traffic_ops/app/lib/API/Tenant.pm @@ -42,14 +42,14 @@ sub index { my @data = (); my @tenants_list = $tenant_utils->get_hierarchic_tenants_list($tenants_data, undef); foreach my $row (@tenants_list) { - if ($tenant_utils->is_tenant_resource_readable($tenants_data, $row->id)) { + if ($tenant_utils->is_tenant_readable($tenants_data, $row->id)) { push( @data, { "id" => $row->id, "name" => $row->name, "active" => \$row->active, "parentId" => $row->parent_id, - "parentName" => ( defined $row->parent_id ) ? $tenant_utils->get_tenant($tenants_data, $row->parent_id)->name : undef, + "parentName" => ( defined $row->parent_id ) ? $tenant_utils->get_tenant_by_id($tenants_data, $row->parent_id)->name : undef, } ); } @@ -68,14 +68,14 @@ sub show { my @data = (); my $rs_data = $self->db->resultset("Tenant")->search( { 'me.id' => $id }); while ( my $row = $rs_data->next ) { - if ($tenant_utils->is_tenant_resource_readable($tenants_data, $row->id)) { + if ($tenant_utils->is_tenant_readable($tenants_data, $row->id)) { push( @data, { "id" => $row->id, "name" => $row->name, "active" => \$row->active, "parentId" => $row->parent_id, - "parentName" => ( defined $row->parent_id ) ? $tenant_utils->get_tenant($tenants_data, $row->parent_id)->name : undef, + "parentName" => ( defined $row->parent_id ) ? $tenant_utils->get_tenant_by_id($tenants_data, $row->parent_id)->name : undef, } ); } @@ -142,18 +142,18 @@ sub update { $current_resource_tenancy = $id; } - if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $current_resource_tenancy)) { + if (!$tenant_utils->is_tenant_writeable($tenants_data, $current_resource_tenancy)) { return $self->forbidden(); #Current owning tenant is not under user's tenancy } - if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $params->{parentId})) { + if (!$tenant_utils->is_tenant_writeable($tenants_data, $params->{parentId})) { return $self->forbidden(); #Parent tenant to be set is not under user's tenancy } if ($params->{parentId} != $tenant->parent) { #parent replacement - if (!defined($tenant_utils->get_tenant($tenants_data, $params->{parentId}))) { + if (!defined($tenant_utils->get_tenant_by_id($tenants_data, $params->{parentId}))) { return $self->alert("Parent tenant does not exists."); } my $parent_depth = $tenant_utils->get_tenant_heirarchy_depth($tenants_data, $params->{parentId}); @@ -248,11 +248,11 @@ sub create { my $tenant_utils = UI::TenantUtils->new($self); my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef); - if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $params->{parentId})) { + if (!$tenant_utils->is_tenant_writeable($tenants_data, $params->{parentId})) { return $self->forbidden(); #Parent tenant to be set is not under user's tenancy } - if (!defined($tenant_utils->get_tenant($tenants_data, $params->{parentId}))) { + if (!defined($tenant_utils->get_tenant_by_id($tenants_data, $params->{parentId}))) { return $self->alert("Parent tenant does not exists."); } @@ -333,7 +333,7 @@ sub delete { my $tenant_utils = UI::TenantUtils->new($self); my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef); - if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $parent_tenant)) { + if (!$tenant_utils->is_tenant_writeable($tenants_data, $parent_tenant)) { return $self->forbidden(); #Parent tenant is not under user's tenancy } http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c8d60294/traffic_ops/app/lib/UI/TenantUtils.pm ---------------------------------------------------------------------- diff --git a/traffic_ops/app/lib/UI/TenantUtils.pm b/traffic_ops/app/lib/UI/TenantUtils.pm index 4162c82..25ea905 100644 --- a/traffic_ops/app/lib/UI/TenantUtils.pm +++ b/traffic_ops/app/lib/UI/TenantUtils.pm @@ -27,6 +27,14 @@ package UI::TenantUtils; # # For now, until the current user tenant ID will come from the jwt, the current user tenant is taken from the DB. # In order to reduce the number of calls from the DB, the current user tenant is taken in the class creation +# +# +# A usage example - examing if a tenant can update a delivery-service: +# my $tenant_utils = UI::TenantUtils->new($self); +# my $tenants_data = $tenant_utils->create_tenants_data_from_db(); +# if (!$tenant_utils->is_ds_writeable($tenants_data, <resource_tenant>)) { +# return $self->forbidden(); #Parent tenant is not under user's tenancy +# } # use Data::Dumper; @@ -37,18 +45,21 @@ sub new { my $class = shift; my $context = shift; my $current_user_tenant = shift; #optional - allowing the user tenancy to be set from outside, for testing capabilities + my $dbh = shift; #optional - allowing the DB handle to be set from outside, for testing capabilities + if (!defined($current_user_tenant)) { # For now, until the current user tenant ID will come from the jwt, the current user tenant is taken from the DB. $current_user_tenant = $context->db->resultset('TmUser')->search( { username => $context->current_user()->{username} } )->get_column('tenant_id')->single(); } - my $dbh = shift; #optional - allowing the DB handle to be set from outside, for testing capabilities if (!defined($dbh)){ $dbh = $context->db } my $self = { dbh => $dbh, + context => $context, #saving the context - use it only for log please... + # In order to reduce the number of calls from the DB, the current user tenant is taken in the class creation. # the below parameters are held temporarily until the info is taken from the jwt current_user_tenant => $current_user_tenant, @@ -60,20 +71,24 @@ sub new { sub create_tenants_data_from_db { my $self = shift; + my $orderby = shift || "name";#some default + my $tenants_data = { tenants_dict => undef, root_tenants => undef, order_by => -1, - ordered_by => undef, + ordered_tenants_list => undef, }; - $tenants_data->{order_by} = shift || "name";#some default + $tenants_data->{order_by} = $orderby; + # read the data from the DB my $tenants_table = $self->{dbh}->resultset("Tenant")->search( undef, { order_by => $tenants_data->{order_by} }); - $tenants_data->{ordered_by} = (); + # build the tenants dict and list. tenants list is kept ordered + $tenants_data->{ordered_tenants_list} = (); $tenants_data->{tenants_dict} = {}; while ( my $row = $tenants_table->next ) { - push (@{ $tenants_data->{ordered_by} }, $row->id); + push (@{ $tenants_data->{ordered_tenants_list} }, $row->id); $tenants_data->{tenants_dict}->{$row->id} = { row => $row, parent => $row->parent_id, @@ -81,8 +96,9 @@ sub create_tenants_data_from_db { } } + #build the root and children tenants lists, ordered by the orderby $tenants_data->{root_tenants} = (); - foreach my $key (@{ $tenants_data->{ordered_by} }) { + foreach my $key (@{ $tenants_data->{ordered_tenants_list} }) { my $value = $tenants_data->{tenants_dict}->{$key}; my $parent = $value->{parent}; if (!defined($parent)) @@ -102,7 +118,7 @@ sub current_user_tenant { return $self->{current_user_tenant}; } -sub get_tenant { +sub get_tenant_by_id { my $self = shift; my $tenants_data = shift; my $tenant_id = shift; @@ -115,7 +131,7 @@ sub get_tenants_list { my $tenants_data = shift; my @result = (); - foreach my $tenant_id (@{ $tenants_data->{ordered_by} }) { + foreach my $tenant_id (@{ $tenants_data->{ordered_tenants_list} }) { push @result, $tenants_data->{tenants_dict}->{$tenant_id}{row}; } @@ -127,18 +143,25 @@ sub get_hierarchic_tenants_list { my $tenants_data = shift; my $tree_root = shift; + #building an heirarchic list via standard DFS. + #First - adding to the stack the root nodes under which we want to get the tenats my @stack = (); if (defined($tree_root)){ push (@stack, $tree_root); } else { + # root is not set, putting all roots, using "reverse" as we push it into a stack + # (from which we pop) and we want to keep the original order push (@stack, reverse(@{$tenants_data->{root_tenants}})); } + #starting the actual DFS, poping from the stack, and pushing the poped node children my @result = (); while (@stack) { my $tenant_id = pop @stack; push (@result, $tenants_data->{tenants_dict}->{$tenant_id}{row}); + # pushing the children in a reverse order, as we working with stack and we + # pop from the end (but want to keep the overall order) push (@stack, reverse(@{$tenants_data->{tenants_dict}->{$tenant_id}{children}})); } @@ -153,14 +176,12 @@ sub is_root_tenant { if (!defined($tenant_id)) { return 0; } - - if (defined($tenants_data->{tenants_dict})) { - return !(defined($tenants_data->{tenants_dict}{$tenant_id}{parent})); - } - return !defined($self->{dbh}->resultset('Tenant')->search( { id => $tenant_id } )->get_column('parent_id')->single()); + + #root <==> parent is undef + return !(defined($tenants_data->{tenants_dict}{$tenant_id}{parent})); } -sub is_tenant_resource_readable { +sub is_tenant_readable { my $self = shift; my $tenants_data = shift; my $resource_tenancy = shift; @@ -168,7 +189,7 @@ sub is_tenant_resource_readable { return $self->_is_resource_accessable ($tenants_data, $resource_tenancy, "r"); } -sub is_tenant_resource_writeable { +sub is_tenant_writeable { my $self = shift; my $tenants_data = shift; my $resource_tenancy = shift; @@ -184,7 +205,8 @@ sub get_tenant_heirarchy_depth { my $tenant_id = shift; if (!defined($tenants_data->{tenants_dict}{$tenant_id})) { - return undef; #tenant does not exists #TODO -ask jeremy how to log + $self->_error("Check tenancy depth - tenant $tenant_id does not exists"); + return undef; } my $iter_id = $tenant_id; @@ -195,7 +217,8 @@ sub get_tenant_heirarchy_depth { $depth++; if ($depth > $self->max_heirarchy_limit()) { - return undef; #heirarchy limit #TODO -ask jeremy how to log + $self->_error("Check tenancy depth for tenant $tenant_id - reached heirarchy limit"); + return undef; } } @@ -210,7 +233,8 @@ sub get_tenant_heirarchy_height { my $tenant_id = shift; if (!defined($tenants_data->{tenants_dict}{$tenant_id})) { - return undef; #tenant does not exists #TODO -ask jeremy how to log + $self->_error("Check tenancy height - tenant $tenant_id does not exists"); + return undef; } #calc tenant height @@ -242,19 +266,23 @@ sub is_anchestor_of { my $descendant_id = shift; if (!defined($anchestor_id)) { - return undef; #anchestor tenant is not defined #TODO -ask jeremy how to log + $self->_error("Check tenants relations - got undef anchestor"); + return undef; } if (!defined($tenants_data->{tenants_dict}{$anchestor_id})) { - return undef; #anchestor tenant does not exists #TODO -ask jeremy how to log + $self->_error("Check tenants relations - tenant $anchestor_id does not exists"); + return undef; } if (!defined($descendant_id)) { - return undef; #descendant tenant is not defined #TODO -ask jeremy how to log + $self->_error("Check tenants relations - got undef descendant"); + return undef; } if (!defined($tenants_data->{tenants_dict}{$descendant_id})) { - return undef; #descendant tenant does not exists #TODO -ask jeremy how to log + $self->_error("Check tenants relations - tenant $descendant_id does not exists"); + return undef; } my $iter_id = $descendant_id; @@ -269,7 +297,8 @@ sub is_anchestor_of { $descendant_depth++; if ($descendant_depth > $self->max_heirarchy_limit()) {#recursion limit - return undef; #TODO -ask jeremy how to log + $self->_error("Tenants relation failed for tenants $anchestor_id / $descendant_id - reached heirarchy limit"); + return undef; } } @@ -286,6 +315,19 @@ sub max_heirarchy_limit { ############################################################## +sub _error { + my $self = shift; + my $message = shift; + + $context = $self->{context}; + if (defined($context)) { + $context->app->log->error($message); + } + else { + print "Error: ", $message, "\n"; + } +} + sub _is_resource_accessable { my $self = shift; my $tenants_data = shift; http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/c8d60294/traffic_ops/app/t/api/1.2/tenant.t ---------------------------------------------------------------------- diff --git a/traffic_ops/app/t/api/1.2/tenant.t b/traffic_ops/app/t/api/1.2/tenant.t index eaff442..6d96f2d 100644 --- a/traffic_ops/app/t/api/1.2/tenant.t +++ b/traffic_ops/app/t/api/1.2/tenant.t @@ -200,70 +200,70 @@ ok $tenant_utils_of_root->get_tenant_heirarchy_height($tenants_data, $tenantE_id ############################ #testing tenancy checks #root tenant - touch entire hierarchy as well as null -ok $tenant_utils_of_root->is_tenant_resource_readable($tenants_data, $root_tenant_id) == 1; -ok $tenant_utils_of_root->is_tenant_resource_writeable($tenants_data, $root_tenant_id) == 1; -ok $tenant_utils_of_root->is_tenant_resource_readable($tenants_data, undef) == 1; -ok $tenant_utils_of_root->is_tenant_resource_writeable($tenants_data, undef) == 1; -ok $tenant_utils_of_root->is_tenant_resource_readable($tenants_data, $tenantA_id) == 1; -ok $tenant_utils_of_root->is_tenant_resource_writeable($tenants_data, $tenantA_id) == 1; -ok $tenant_utils_of_root->is_tenant_resource_readable($tenants_data, $tenantE_id) == 1; -ok $tenant_utils_of_root->is_tenant_resource_writeable($tenants_data, $tenantE_id) == 1; +ok $tenant_utils_of_root->is_tenant_readable($tenants_data, $root_tenant_id) == 1; +ok $tenant_utils_of_root->is_tenant_writeable($tenants_data, $root_tenant_id) == 1; +ok $tenant_utils_of_root->is_tenant_readable($tenants_data, undef) == 1; +ok $tenant_utils_of_root->is_tenant_writeable($tenants_data, undef) == 1; +ok $tenant_utils_of_root->is_tenant_readable($tenants_data, $tenantA_id) == 1; +ok $tenant_utils_of_root->is_tenant_writeable($tenants_data, $tenantA_id) == 1; +ok $tenant_utils_of_root->is_tenant_readable($tenants_data, $tenantE_id) == 1; +ok $tenant_utils_of_root->is_tenant_writeable($tenants_data, $tenantE_id) == 1; my $tenant_utils_of_a = UI::TenantUtils->new(undef, $tenantA_id, $schema); my $tenants_data_of_a = $tenant_utils_of_a->create_tenants_data_from_db(); #parent - no access -ok $tenant_utils_of_a->is_tenant_resource_readable($tenants_data_of_a, $root_tenant_id) == 0; -ok $tenant_utils_of_a->is_tenant_resource_writeable($tenants_data_of_a, $root_tenant_id) == 0; +ok $tenant_utils_of_a->is_tenant_readable($tenants_data_of_a, $root_tenant_id) == 0; +ok $tenant_utils_of_a->is_tenant_writeable($tenants_data_of_a, $root_tenant_id) == 0; #undef - all have access -ok $tenant_utils_of_a->is_tenant_resource_readable($tenants_data_of_a, undef) == 1; -ok $tenant_utils_of_a->is_tenant_resource_writeable($tenants_data_of_a, undef) == 1; +ok $tenant_utils_of_a->is_tenant_readable($tenants_data_of_a, undef) == 1; +ok $tenant_utils_of_a->is_tenant_writeable($tenants_data_of_a, undef) == 1; #itself - full access -ok $tenant_utils_of_a->is_tenant_resource_readable($tenants_data_of_a, $tenantA_id) == 1; -ok $tenant_utils_of_a->is_tenant_resource_writeable($tenants_data_of_a, $tenantA_id) == 1; +ok $tenant_utils_of_a->is_tenant_readable($tenants_data_of_a, $tenantA_id) == 1; +ok $tenant_utils_of_a->is_tenant_writeable($tenants_data_of_a, $tenantA_id) == 1; # child - full access -ok $tenant_utils_of_a->is_tenant_resource_readable($tenants_data_of_a, $tenantE_id) == 1; -ok $tenant_utils_of_a->is_tenant_resource_writeable($tenants_data_of_a, $tenantE_id) == 1; +ok $tenant_utils_of_a->is_tenant_readable($tenants_data_of_a, $tenantE_id) == 1; +ok $tenant_utils_of_a->is_tenant_writeable($tenants_data_of_a, $tenantE_id) == 1; # Brother - no access -ok $tenant_utils_of_a->is_tenant_resource_readable($tenants_data_of_a, $tenantB_id) == 0; -ok $tenant_utils_of_a->is_tenant_resource_writeable($tenants_data_of_a, $tenantB_id) == 0; +ok $tenant_utils_of_a->is_tenant_readable($tenants_data_of_a, $tenantB_id) == 0; +ok $tenant_utils_of_a->is_tenant_writeable($tenants_data_of_a, $tenantB_id) == 0; #leaf test my $tenant_utils_of_d = UI::TenantUtils->new(undef, $tenantD_id, $schema); my $tenants_data_of_d = $tenant_utils_of_d->create_tenants_data_from_db(); #anchestor - no access -ok $tenant_utils_of_d->is_tenant_resource_readable($tenants_data_of_d, $root_tenant_id) == 0; -ok $tenant_utils_of_d->is_tenant_resource_writeable($tenants_data_of_d, $root_tenant_id) == 0; +ok $tenant_utils_of_d->is_tenant_readable($tenants_data_of_d, $root_tenant_id) == 0; +ok $tenant_utils_of_d->is_tenant_writeable($tenants_data_of_d, $root_tenant_id) == 0; #undef - all have access -ok $tenant_utils_of_d->is_tenant_resource_readable($tenants_data_of_d, undef) == 1; -ok $tenant_utils_of_d->is_tenant_resource_writeable($tenants_data_of_d, undef) == 1; +ok $tenant_utils_of_d->is_tenant_readable($tenants_data_of_d, undef) == 1; +ok $tenant_utils_of_d->is_tenant_writeable($tenants_data_of_d, undef) == 1; # parent - no access -ok $tenant_utils_of_d->is_tenant_resource_readable($tenants_data_of_d, $tenantA_id) == 0; -ok $tenant_utils_of_d->is_tenant_resource_writeable($tenants_data_of_d, $tenantA_id) == 0; +ok $tenant_utils_of_d->is_tenant_readable($tenants_data_of_d, $tenantA_id) == 0; +ok $tenant_utils_of_d->is_tenant_writeable($tenants_data_of_d, $tenantA_id) == 0; # itself - full access -ok $tenant_utils_of_d->is_tenant_resource_readable($tenants_data_of_d, $tenantD_id) == 1; -ok $tenant_utils_of_d->is_tenant_resource_writeable($tenants_data_of_d, $tenantD_id) == 1; +ok $tenant_utils_of_d->is_tenant_readable($tenants_data_of_d, $tenantD_id) == 1; +ok $tenant_utils_of_d->is_tenant_writeable($tenants_data_of_d, $tenantD_id) == 1; # uncle - no access -ok $tenant_utils_of_d->is_tenant_resource_readable($tenants_data_of_d, $tenantB_id) == 0; -ok $tenant_utils_of_d->is_tenant_resource_writeable($tenants_data_of_d, $tenantB_id) == 0; +ok $tenant_utils_of_d->is_tenant_readable($tenants_data_of_d, $tenantB_id) == 0; +ok $tenant_utils_of_d->is_tenant_writeable($tenants_data_of_d, $tenantB_id) == 0; #inactive - nothing can do my $tenant_utils_of_e = UI::TenantUtils->new(undef, $tenantE_id, $schema); my $tenants_data_of_e = $tenant_utils_of_e->create_tenants_data_from_db(); #anchestor - no access -ok $tenant_utils_of_e->is_tenant_resource_readable($tenants_data_of_e, $root_tenant_id) == 0; -ok $tenant_utils_of_e->is_tenant_resource_writeable($tenants_data_of_e, $root_tenant_id) == 0; +ok $tenant_utils_of_e->is_tenant_readable($tenants_data_of_e, $root_tenant_id) == 0; +ok $tenant_utils_of_e->is_tenant_writeable($tenants_data_of_e, $root_tenant_id) == 0; #undef - all have access -ok $tenant_utils_of_e->is_tenant_resource_readable($tenants_data_of_e, undef) == 0; -ok $tenant_utils_of_e->is_tenant_resource_writeable($tenants_data_of_e, undef) == 0; +ok $tenant_utils_of_e->is_tenant_readable($tenants_data_of_e, undef) == 0; +ok $tenant_utils_of_e->is_tenant_writeable($tenants_data_of_e, undef) == 0; # parent - no access -ok $tenant_utils_of_e->is_tenant_resource_readable($tenants_data_of_e, $tenantA_id) == 0; -ok $tenant_utils_of_e->is_tenant_resource_writeable($tenants_data_of_e, $tenantA_id) == 0; +ok $tenant_utils_of_e->is_tenant_readable($tenants_data_of_e, $tenantA_id) == 0; +ok $tenant_utils_of_e->is_tenant_writeable($tenants_data_of_e, $tenantA_id) == 0; # itself - full access -ok $tenant_utils_of_e->is_tenant_resource_readable($tenants_data_of_e, $tenantE_id) == 0; -ok $tenant_utils_of_e->is_tenant_resource_writeable($tenants_data_of_e, $tenantE_id) == 0; +ok $tenant_utils_of_e->is_tenant_readable($tenants_data_of_e, $tenantE_id) == 0; +ok $tenant_utils_of_e->is_tenant_writeable($tenants_data_of_e, $tenantE_id) == 0; # uncle - no access -ok $tenant_utils_of_e->is_tenant_resource_readable($tenants_data_of_e, $tenantB_id) == 0; -ok $tenant_utils_of_e->is_tenant_resource_writeable($tenants_data_of_e, $tenantB_id) == 0; +ok $tenant_utils_of_e->is_tenant_readable($tenants_data_of_e, $tenantB_id) == 0; +ok $tenant_utils_of_e->is_tenant_writeable($tenants_data_of_e, $tenantB_id) == 0; #################