You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficcontrol.apache.org by GitBox <gi...@apache.org> on 2018/09/10 17:12:06 UTC

[GitHub] dneuman64 closed pull request #2796: adds the ability to assign resolvers across federations

dneuman64 closed pull request #2796: adds the ability to assign resolvers across federations
URL: https://github.com/apache/trafficcontrol/pull/2796
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/traffic_ops/app/db/seeds.sql b/traffic_ops/app/db/seeds.sql
index 7959d3c85..93aceb38c 100644
--- a/traffic_ops/app/db/seeds.sql
+++ b/traffic_ops/app/db/seeds.sql
@@ -550,6 +550,7 @@ insert into api_capability (http_method, route, capability) values ('POST', 'fed
 insert into api_capability (http_method, route, capability) values ('DELETE', 'federations/*/deliveryservices/*', 'federations-write') ON CONFLICT (http_method, route, capability) DO NOTHING;
 insert into api_capability (http_method, route, capability) values ('GET', 'federations/*/federation_resolvers', 'federations-read') ON CONFLICT (http_method, route, capability) DO NOTHING;
 insert into api_capability (http_method, route, capability) values ('POST', 'federations/*/federation_resolvers', 'federations-write') ON CONFLICT (http_method, route, capability) DO NOTHING;
+insert into api_capability (http_method, route, capability) values ('GET', 'federation_resolvers', 'federations-read') ON CONFLICT (http_method, route, capability) DO NOTHING;
 insert into api_capability (http_method, route, capability) values ('POST', 'federation_resolvers', 'federations-write') ON CONFLICT (http_method, route, capability) DO NOTHING;
 insert into api_capability (http_method, route, capability) values ('DELETE', 'federation_resolvers/*', 'federations-write') ON CONFLICT (http_method, route, capability) DO NOTHING;
 -- hardware info
diff --git a/traffic_ops/app/lib/API/FederationFederationResolver.pm b/traffic_ops/app/lib/API/FederationFederationResolver.pm
index c8d6d94d8..34ad8f518 100644
--- a/traffic_ops/app/lib/API/FederationFederationResolver.pm
+++ b/traffic_ops/app/lib/API/FederationFederationResolver.pm
@@ -25,7 +25,7 @@ sub index {
     my $fed_id  = $self->param('fedId');
 
     my @data;
-    my $rs_data = $self->db->resultset("FederationFederationResolver")->search( { 'federation' => $fed_id }, { prefetch => [ 'federation_resolver' ] } );
+    my $rs_data = $self->db->resultset("FederationFederationResolver")->search( { 'federation' => $fed_id }, { prefetch => [ 'federation_resolver' ], order_by => 'federation_resolver.ip_address' } );
     while ( my $row = $rs_data->next ) {
         push(
             @data, {
diff --git a/traffic_ops/app/lib/API/FederationResolver.pm b/traffic_ops/app/lib/API/FederationResolver.pm
index f77e4a6ad..38f8f074d 100644
--- a/traffic_ops/app/lib/API/FederationResolver.pm
+++ b/traffic_ops/app/lib/API/FederationResolver.pm
@@ -25,6 +25,22 @@ use Validate::Tiny ':all';
 use Net::CIDR;
 use Data::Validate::IP qw(is_ipv4 is_ipv6);
 
+sub index {
+    my $self = shift;
+    my @data;
+    my $rs_data = $self->db->resultset("FederationResolver")->search( undef, { prefetch => ['type'] } );
+    while ( my $row = $rs_data->next ) {
+        push(
+            @data, {
+                "id"        => $row->id,
+                "ipAddress" => $row->ip_address,
+                "type"      => $row->type->name
+            }
+        );
+    }
+    $self->success( \@data );
+}
+
 sub create {
     my $self        = shift;
     my $params      = $self->req->json;
diff --git a/traffic_ops/app/lib/TrafficOpsRoutes.pm b/traffic_ops/app/lib/TrafficOpsRoutes.pm
index a371442c1..7c56a5bca 100644
--- a/traffic_ops/app/lib/TrafficOpsRoutes.pm
+++ b/traffic_ops/app/lib/TrafficOpsRoutes.pm
@@ -634,6 +634,7 @@ sub api_routes {
 	$r->post( "/api/$version/federations/:fedId/federation_resolvers" => [ id => qr/\d+/ ] )->over( authenticated => 1, not_ldap => 1 )->to( 'FederationFederationResolver#assign_fed_resolver_to_federation', namespace => $namespace );
 
 	# -- FEDERATION RESOLVERS
+	$r->get( "/api/$version/federation_resolvers" => [ id => qr/\d+/ ] )->over( authenticated => 1, not_ldap => 1 )->to( 'FederationResolver#index', namespace => $namespace );
 	$r->post( "/api/$version/federation_resolvers" => [ id => qr/\d+/ ] )->over( authenticated => 1, not_ldap => 1 )->to( 'FederationResolver#create', namespace => $namespace );
 	$r->delete( "/api/$version/federation_resolvers/:id" => [ id => qr/\d+/ ] )->over( authenticated => 1, not_ldap => 1 )->to( 'FederationResolver#delete', namespace => $namespace );
 
diff --git a/traffic_portal/app/src/app.js b/traffic_portal/app/src/app.js
index 7805968b2..a81502eea 100644
--- a/traffic_portal/app/src/app.js
+++ b/traffic_portal/app/src/app.js
@@ -349,6 +349,7 @@ var trafficPortal = angular.module('trafficPortal', [
         require('./common/modules/table/divisions').name,
         require('./common/modules/table/divisionRegions').name,
         require('./common/modules/table/endpoints').name,
+        require('./common/modules/table/federationResolvers').name,
         require('./common/modules/table/jobs').name,
         require('./common/modules/table/origins').name,
         require('./common/modules/table/physLocations').name,
diff --git a/traffic_portal/app/src/common/api/FederationResolverService.js b/traffic_portal/app/src/common/api/FederationResolverService.js
index cf240f518..6e18e306b 100644
--- a/traffic_portal/app/src/common/api/FederationResolverService.js
+++ b/traffic_portal/app/src/common/api/FederationResolverService.js
@@ -19,13 +19,17 @@
 
 var FederationResolverService = function(Restangular, $http, $q, ENV, locationUtils, messageModel) {
 
+	this.getFederationResolvers = function(queryParams) {
+		return Restangular.all('federation_resolvers').getList(queryParams);
+	};
+
 	this.createFederationResolver = function(fedResolver) {
 		var deferred = $q.defer();
 
 		$http.post(ENV.api['root'] + 'federation_resolvers', fedResolver)
 			.then(
 				function(result) {
-					deferred.resolve(result.data.response);
+					deferred.resolve(result);
 				},
 				function(fault) {
 					deferred.reject(fault);
@@ -35,18 +39,6 @@ var FederationResolverService = function(Restangular, $http, $q, ENV, locationUt
 		return deferred.promise;
 	};
 
-	this.deleteFederationResolver = function(fedResId) {
-		return Restangular.one('federation_resolvers', fedResId).remove()
-			.then(
-				function() {
-					messageModel.setMessages([ { level: 'success', text: 'Federation resolver deleted' } ], false);
-				},
-				function(fault) {
-					messageModel.setMessages(fault.data.alerts, true);
-				}
-			);
-	};
-
 	this.assignFederationResolvers = function(fedId, fedResIds, replace) {
 		return $http.post(ENV.api['root'] + 'federations/' + fedId + '/federation_resolvers', { fedResolverIds: fedResIds, replace: replace })
 			.then(
diff --git a/traffic_portal/app/src/common/modules/form/federation/edit/FormEditFederationController.js b/traffic_portal/app/src/common/modules/form/federation/edit/FormEditFederationController.js
index 564f75474..f29eee7db 100644
--- a/traffic_portal/app/src/common/modules/form/federation/edit/FormEditFederationController.js
+++ b/traffic_portal/app/src/common/modules/form/federation/edit/FormEditFederationController.js
@@ -29,18 +29,11 @@ var FormEditFederationController = function(cdn, federation, resolvers, delivery
 			});
 	};
 
-	var deleteFederationResolver = function(fedRes) {
-		federationResolverService.deleteFederationResolver(fedRes.id)
-			.then(function() {
-				$state.reload(); // reloads all the resolves for the view
-			});
-	};
-
 	var createFederationResolver = function(fedRes) {
 		federationResolverService.createFederationResolver(fedRes)
 			.then(
 				function(result) {
-					assignFederationResolver(federation.id, result.id);
+					messageModel.setMessages(result.data.alerts, false);
 				},
 				function(fault) {
 					messageModel.setMessages(fault.data.alerts, false);
@@ -48,8 +41,8 @@ var FormEditFederationController = function(cdn, federation, resolvers, delivery
 			);
 	};
 
-	var assignFederationResolver = function(fedId, fedResId) {
-		federationResolverService.assignFederationResolvers(fedId, [ fedResId ], false)
+	var assignFederationResolvers = function(fedId, fedResIds) {
+		federationResolverService.assignFederationResolvers(fedId, fedResIds, true)
 			.then(function() {
 				$state.reload(); // reloads all the resolves for the view
 			});
@@ -97,10 +90,10 @@ var FormEditFederationController = function(cdn, federation, resolvers, delivery
 		});
 	};
 
-	$scope.confirmDeleteResolver = function(resolver) {
+	$scope.confirmRemoveResolver = function(resolverToRemove) {
 		var params = {
-			title: 'Delete Federation Resolver: ' + resolver.ipAddress,
-			message: 'Are you sure you want to delete this federation resolver and remove it from the ' + federation.cname + ' federation?'
+			title: 'Remove Federation Resolver: ' + resolverToRemove.ipAddress,
+			message: 'Are you sure you want to remove this federation resolver from the ' + federation.cname + ' federation?'
 		};
 		var modalInstance = $uibModal.open({
 			templateUrl: 'common/modules/dialog/confirm/dialog.confirm.tpl.html',
@@ -113,7 +106,9 @@ var FormEditFederationController = function(cdn, federation, resolvers, delivery
 			}
 		});
 		modalInstance.result.then(function() {
-			deleteFederationResolver(resolver);
+			var resolvers = _.filter($scope.resolvers, function(res){ return res.id != resolverToRemove.id; });
+			var resolverIds = _.pluck(resolvers, 'id');
+			assignFederationResolvers($scope.federation.id, resolverIds)
 		}, function () {
 			// do nothing
 		});
@@ -143,6 +138,31 @@ var FormEditFederationController = function(cdn, federation, resolvers, delivery
 		});
 	};
 
+	$scope.selectResolvers = function() {
+		var modalInstance = $uibModal.open({
+			templateUrl: 'common/modules/table/federationResolvers/table.assignFedResolvers.tpl.html',
+			controller: 'TableAssignFedResolversController',
+			size: 'lg',
+			resolve: {
+				federation: function() {
+					return federation;
+				},
+				resolvers: function(federationResolverService) {
+					return federationResolverService.getFederationResolvers();
+				},
+				assignedResolvers: function() {
+					return resolvers;
+				}
+			}
+		});
+		modalInstance.result.then(function(selectedResolverIds) {
+			debugger;
+			assignFederationResolvers($scope.federation.id, selectedResolverIds);
+		}, function () {
+			// do nothing
+		});
+	};
+
 };
 
 FormEditFederationController.$inject = ['cdn', 'federation', 'resolvers', 'deliveryServices', 'federationDeliveryServices', '$scope', '$state', '$controller', '$uibModal', '$anchorScroll', 'locationUtils', 'federationService', 'federationResolverService', 'messageModel'];
diff --git a/traffic_portal/app/src/common/modules/form/federation/form.federation.tpl.html b/traffic_portal/app/src/common/modules/form/federation/form.federation.tpl.html
index c7ddd2e6a..6b7dd6538 100644
--- a/traffic_portal/app/src/common/modules/form/federation/form.federation.tpl.html
+++ b/traffic_portal/app/src/common/modules/form/federation/form.federation.tpl.html
@@ -26,7 +26,8 @@
             <li class="active">{{cname}}</li>
         </ol>
         <div class="pull-right" ng-show="!settings.isNew">
-            <button class="btn btn-primary" title="Create Resolver" ng-click="createResolver()">Create Resolver</button>
+            <button class="btn btn-primary" title="Create New Resolver" ng-click="createResolver()"><i class="fa fa-plus"></i></button>
+            <button class="btn btn-primary" title="Link Resolvers to Federation" ng-click="selectResolvers()"><i class="fa fa-link"></i></button>
             <div class="btn-group" role="group" uib-dropdown is-open="more.isopen">
                 <button type="button" class="btn btn-default dropdown-toggle" uib-dropdown-toggle aria-haspopup="true" aria-expanded="false">
                     More&nbsp;
@@ -91,7 +92,9 @@
             </fieldset>
             <div ng-if="!settings.isNew">
                 <fieldset>
-                    <legend>Federation Resolvers</legend>
+                    <legend>
+                        <div>Federation Resolvers</div>
+                    </legend>
                     <table class="table responsive-utilities jambo_table" ng-show="resolvers.length > 0">
                         <thead>
                         <tr class="headings">
@@ -104,7 +107,7 @@
                         <tr ng-repeat="resolver in ::resolvers">
                             <td>{{::resolver.ipAddress}}</td>
                             <td>{{::resolver.type}}</td>
-                            <td style="width:20px"><button type="button" class="btn btn-link" title="Delete Federation Resolver" ng-click="confirmDeleteResolver(resolver)"><i class="fa fa-trash"></i></button></td>
+                            <td style="width:20px"><button type="button" class="btn btn-link" title="Remove Federation Resolver" ng-click="confirmRemoveResolver(resolver)"><i class="fa fa-chain-broken"></i></button></td>
                         </tr>
                         </tbody>
                     </table>
diff --git a/traffic_portal/app/src/common/modules/table/federationResolvers/TableAssignFedResolversController.js b/traffic_portal/app/src/common/modules/table/federationResolvers/TableAssignFedResolversController.js
new file mode 100644
index 000000000..31d0aafed
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/table/federationResolvers/TableAssignFedResolversController.js
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var TableAssignFedResolversController = function(federation, resolvers, assignedResolvers, $scope, $uibModalInstance) {
+
+    var selectedResolvers = [];
+
+    var addAll = function() {
+        markVisibleResolvers(true);
+    };
+
+    var removeAll = function() {
+        markVisibleResolvers(false);
+    };
+
+    var markVisibleResolvers = function(selected) {
+        var visibleResolverIds = $('#fedResolversTable tr.resolver-row').map(
+                function() {
+                    return parseInt($(this).attr('id'));
+                }).get();
+        $scope.resolvers = _.map(resolvers, function(resolver) {
+            if (visibleResolverIds.includes(resolver.id)) {
+                resolver['selected'] = selected;
+            }
+            return resolver;
+        });
+        updateSelectedCount();
+    };
+
+    var updateSelectedCount = function() {
+        selectedResolvers = _.filter($scope.resolvers, function(resolver) { return resolver['selected'] == true; } );
+        $('div.selected-count').html('<b>' + selectedResolvers.length + ' resolvers selected</b>');
+    };
+
+    $scope.federation = federation;
+
+    $scope.resolvers = _.map(resolvers, function(resolver) {
+        var isAssigned = _.find(assignedResolvers, function(assignedResolver) { return assignedResolver.id == resolver.id });
+        if (isAssigned) {
+            resolver['selected'] = true;
+        }
+        return resolver;
+    });
+
+    $scope.selectAll = function($event) {
+        var checkbox = $event.target;
+        if (checkbox.checked) {
+            addAll();
+        } else {
+            removeAll();
+        }
+    };
+
+    $scope.onChange = function() {
+        updateSelectedCount();
+    };
+
+    $scope.submit = function() {
+        var selectedResolverIds = _.pluck(selectedResolvers, 'id');
+        $uibModalInstance.close(selectedResolverIds);
+    };
+
+    $scope.cancel = function () {
+        $uibModalInstance.dismiss('cancel');
+    };
+
+    angular.element(document).ready(function () {
+        var fedResolversTable = $('#fedResolversTable').dataTable({
+            "scrollY": "60vh",
+            "paging": false,
+            "order": [[ 1, 'asc' ]],
+            "dom": '<"selected-count">frtip',
+            "columnDefs": [
+                { 'orderable': false, 'targets': 0 },
+                { "width": "5%", "targets": 0 }
+            ],
+            "stateSave": false
+        });
+        fedResolversTable.on( 'search.dt', function () {
+            $("#selectAllCB").removeAttr("checked"); // uncheck the all box when filtering
+        } );
+        updateSelectedCount();
+    });
+
+};
+
+TableAssignFedResolversController.$inject = ['federation', 'resolvers', 'assignedResolvers', '$scope', '$uibModalInstance'];
+module.exports = TableAssignFedResolversController;
diff --git a/traffic_portal/app/src/common/modules/table/federationResolvers/index.js b/traffic_portal/app/src/common/modules/table/federationResolvers/index.js
new file mode 100644
index 000000000..9dea2b50d
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/table/federationResolvers/index.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports = angular.module('trafficPortal.table.federationResolvers', [])
+	.controller('TableAssignFedResolversController', require('./TableAssignFedResolversController'));
diff --git a/traffic_portal/app/src/common/modules/table/federationResolvers/table.assignFedResolvers.tpl.html b/traffic_portal/app/src/common/modules/table/federationResolvers/table.assignFedResolvers.tpl.html
new file mode 100644
index 000000000..75a03bfdd
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/table/federationResolvers/table.assignFedResolvers.tpl.html
@@ -0,0 +1,47 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
+    <h3 class="modal-title">Assign Resolvers to {{::federation.cname}}</h3>
+</div>
+<div class="modal-body">
+    <table id="fedResolversTable" class="table responsive-utilities jambo_table" style="table-layout:fixed; width:100%;">
+        <thead>
+        <tr class="headings">
+            <th style="padding-left: 10px;"><input id="selectAllCB" type="checkbox" ng-click="selectAll($event)"></th>
+            <th>IP</th>
+            <th>Type</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr id="{{::r.id}}" class="resolver-row" ng-repeat="r in ::resolvers">
+            <td><input type="checkbox" ng-checked="r.selected" ng-model="r.selected" ng-change="onChange()"></td>
+            <td data-search="^{{::r.ipAddress}}$">{{::r.ipAddress}}</td>
+            <td data-search="^{{::r.type}}$">{{::r.type}}</td>
+        </tr>
+        </tbody>
+    </table>
+</div>
+<div class="modal-footer">
+    <button class="btn btn-link" ng-click="cancel()">cancel</button>
+    <button class="btn btn-primary" ng-click="submit()">Submit</button>
+</div>


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services