You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by mi...@apache.org on 2017/05/24 02:40:08 UTC

[03/14] incubator-trafficcontrol git commit: Adding capabilities & api_capalities APIs

Adding capabilities & api_capalities APIs

(cherry picked from commit db31205f6cdae581f072a34347f057441721b31c)


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/9546e8ad
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/9546e8ad
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/9546e8ad

Branch: refs/heads/master
Commit: 9546e8ad26fac8a221880867a5e62f00cf9cbbf2
Parents: 5392f50
Author: naamashoresh <na...@qwilt.com>
Authored: Thu May 4 10:28:18 2017 +0300
Committer: Jeremy Mitchell <mi...@gmail.com>
Committed: Tue May 23 20:39:02 2017 -0600

----------------------------------------------------------------------
 traffic_ops/app/lib/API/ApiCapability.pm | 258 ++++++++++++++++++++++++++
 traffic_ops/app/lib/API/Capability.pm    | 185 ++++++++++++++++++
 traffic_ops/app/lib/TrafficOpsRoutes.pm  |  17 ++
 3 files changed, 460 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/9546e8ad/traffic_ops/app/lib/API/ApiCapability.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/API/ApiCapability.pm b/traffic_ops/app/lib/API/ApiCapability.pm
new file mode 100644
index 0000000..2e2ca73
--- /dev/null
+++ b/traffic_ops/app/lib/API/ApiCapability.pm
@@ -0,0 +1,258 @@
+package API::ApiCapability;
+#
+#
+# Licensed 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.
+#
+#
+#
+
+use UI::Utils;
+
+use Mojo::Base 'Mojolicious::Controller';
+use Data::Dumper;
+
+
+
+my $finfo = __FILE__ . ":";
+
+my %valid_http_methods = map { $_ => 1 } ('GET', 'POST', 'PUT', 'PATCH', 'DELETE');
+
+sub all {
+	my $self = shift;
+	my @data;
+	my $orderby = "capability";
+	$orderby = $self->param('orderby') if ( defined $self->param('orderby') );
+
+	my $rs_data = $self->db->resultset("ApiCapability")->search( undef, { order_by => $orderby } );
+	while ( my $row = $rs_data->next ) {
+		push(
+			@data, {
+				"id"          	=> $row->id,
+				"httpMethod"	=> $row->http_method,
+				"route" 		=> $row->route,
+				"capName"   	=> $row->capability->name,
+				"lastUpdated" 	=> $row->last_updated
+			}
+		);
+	}
+	$self->success( \@data );
+}
+
+
+sub renderResults {
+	my $self = shift;
+	my $rs_data = shift;
+
+	my @data = ();
+	while ( my $row = $rs_data->next ) {
+		push(
+			@data, {
+				"id"          	=> $row->id,
+				"httpMethod"	=> $row->http_method,
+				"route" 		=> $row->route,
+				"capName"   	=> $row->capability->name,
+				"lastUpdated" 	=> $row->last_updated
+			}
+		);
+	}
+	$self->success( \@data );
+}
+
+sub capName {
+	my $self = shift;
+	my $capability = $self->param('name');
+
+	my $rs_data = $self->db->resultset("ApiCapability")->search( 'me.capability' => $capability );
+	$self->renderResults( $rs_data ) ;
+}
+
+sub index {
+	my $self = shift;
+	my $id = $self->param('id');
+
+	my $rs_data = $self->db->resultset("ApiCapability")->search( 'me.id' => $id );
+	$self->renderResults( $rs_data ) ;
+}
+
+sub is_mapping_valid {
+	my $self = shift;
+	my $id = shift;
+	my $http_method = shift;
+	my $route = shift;
+	my $capability = shift;
+
+	if ( !defined($http_method) ) {
+		return ( undef, "HTTP method is required." );
+	}
+
+	if ( !exists( $valid_http_methods{ $http_method } ) ) {
+		return ( undef, "HTTP method \'$http_method\' is invalid. Valid values are: " . join(", ", sort keys %valid_http_methods ) );
+	}
+
+	if ( !defined($route) or $route eq "" ) {
+		return ( undef, "Route is required." );
+	}
+
+	if ( !defined($capability) or $capability eq "" ) {
+		return (undef, "Capability name is required." );
+	}
+	# check if capability exists
+	my $rs_data = $self->db->resultset("Capability")->search( { 'name' => { 'like', $capability } } )->single();
+	if (!defined($rs_data)) {
+		return (undef, "Capability '$capability' does not exist." );
+	}
+
+	# search a mapping for the same http_method & route
+	$rs_data = $self->db->resultset("ApiCapability")->search( { 'route' => { 'like', $route } } )->search( {
+		'http_method' => { '=', $http_method } } )->single();
+	# if adding a new entry, make sure it is unique
+	if ( !defined( $id ) ) {
+		if (defined($rs_data)) {
+			my $allocated_capability = $rs_data->capability->name;
+			return (undef, "HTTP method '$http_method', route '$route' are already mapped to capability: $allocated_capability" );
+		}
+	}
+	else {
+		if (defined($rs_data)) {
+			my $lid = $rs_data->id;
+			if ($lid ne $id) {
+				my $allocated_capability = $rs_data->capability->name;
+				return (undef, "HTTP method '$http_method', route '$route' are already mapped to capability: $allocated_capability" );
+			}
+		}
+	}
+
+	return ( 1, undef );
+}
+
+sub create {
+	my $self = shift;
+	my $params = $self->req->json;
+
+	if ( !&is_oper($self) ) {
+		return $self->forbidden();
+	}
+
+	if ( !defined($params) ) {
+		return $self->alert("Parameters must be in JSON format.");
+	}
+
+	my $http_method = $params->{httpMethod} if defined($params->{httpMethod});
+	my $route = $params->{route} if defined($params->{route});
+	my $capability = $params->{capName} if defined($params->{capName});
+	my $id = undef;
+
+	my ( $is_valid, $errStr ) = $self->is_mapping_valid( $id, $http_method, $route, $capability );
+	if ( !$is_valid ) {
+		return $self->alert( $errStr );
+	}
+
+	my $values = {
+		id 			=> $self->db->resultset('ApiCapability')->get_column('id')->max() + 1,
+		http_method	=> $http_method,
+		route		=> $route,
+		capability	=> $capability
+	};
+
+	my $insert = $self->db->resultset('ApiCapability')->create($values);
+	my $rs = $insert->insert();
+	if ($rs) {
+		my $response;
+		$response->{id}				= $rs->id;
+		$response->{httpMethod}		= $rs->http_method;
+		$response->{route}			= $rs->route;
+		$response->{capName}		= $rs->capability->name;
+		$response->{lastUpdated}	= $rs->last_updated;
+
+		&log( $self, "Created API-Capability mapping: '$response->{httpMethod}', '$response->{route}', '$response->{capName}' for id: " . $response->{id}, "APICHANGE" );
+
+		return $self->success( $response, "API-Capability mapping was created." );
+	}
+	else {
+		return $self->alert( "API-Capability mapping creation failed." );
+	}
+}
+
+sub update {
+	my $self = shift;
+	my $id = $self->param('id');
+	my $params = $self->req->json;
+
+	if ( !&is_oper($self) ) {
+		return $self->forbidden();
+	}
+
+	if ( !defined($params) ) {
+		return $self->alert("Parameters must be in JSON format.");
+	}
+
+	my $http_method = $params->{httpMethod} if defined($params->{httpMethod});
+	my $route = $params->{route} if defined($params->{route});
+	my $capability = $params->{capName} if defined($params->{capName});
+
+	my $mapping = $self->db->resultset('ApiCapability')->find( { id => $id } );
+	if ( !defined($mapping) ) {
+		return $self->not_found();
+	}
+
+	my ( $is_valid, $errStr ) = $self->is_mapping_valid( $id, $http_method, $route, $capability );
+	if ( !$is_valid ) {
+		return $self->alert( $errStr );
+	}
+
+	my $values = {
+		http_method	=> $http_method,
+		route		=> $route,
+		capability	=> $capability
+	};
+
+	my $rs = $mapping->update($values);
+	if ($rs) {
+		my $response;
+		$response->{id}				= $rs->id;
+		$response->{httpMethod}		= $rs->http_method;
+		$response->{route}			= $rs->route;
+		$response->{capName}		= $rs->capability->name;
+		$response->{lastUpdated}	= $rs->last_updated;
+
+		&log( $self, "Updated API-Capability mapping: '$response->{httpMethod}', '$response->{route}', '$response->{capName}' for id: " . $response->{id}, "APICHANGE" );
+
+		return $self->success( $response, "API-Capability mapping was updated." );
+	}
+	else {
+		return $self->alert( "API-Capability mapping update failed." );
+	}
+}
+
+sub delete {
+	my $self = shift;
+	my $id     = $self->param('id');
+
+	if ( !&is_oper($self) ) {
+		return $self->forbidden();
+	}
+
+	my $mapping = $self->db->resultset('ApiCapability')->find( { id => $id } );
+	if ( !defined($mapping) ) {
+		return $self->not_found();
+	}
+
+	my $rs = $mapping->delete();
+	if ($rs) {
+		return $self->success_message("API-capability mapping deleted.");
+	} else {
+		return $self->alert( "API-capability mapping deletion failed." );
+	}
+}
+
+1;

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/9546e8ad/traffic_ops/app/lib/API/Capability.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/API/Capability.pm b/traffic_ops/app/lib/API/Capability.pm
new file mode 100644
index 0000000..695434b
--- /dev/null
+++ b/traffic_ops/app/lib/API/Capability.pm
@@ -0,0 +1,185 @@
+package API::Capability;
+#
+#
+# Licensed 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.
+#
+#
+#
+
+use UI::Utils;
+
+use Mojo::Base 'Mojolicious::Controller';
+use Data::Dumper;
+
+my $finfo = __FILE__ . ":";
+
+sub all {
+	my $self = shift;
+	my @data;
+	my $orderby = "name";
+	$orderby = $self->param('orderby') if ( defined $self->param('orderby') );
+
+	my $rs_data = $self->db->resultset("Capability")->search( undef, { order_by => $orderby } );
+	while ( my $row = $rs_data->next ) {
+		push(
+			@data, {
+				"name"          => $row->name,
+				"description"	=> $row->description,
+				"lastUpdated" 	=> $row->last_updated
+			}
+		);
+	}
+	$self->success( \@data );
+}
+
+sub name {
+	my $self = shift;
+	my $name = $self->param('name');
+
+	my $rs_data = $self->db->resultset("Capability")->search( 'me.name' => $name  );
+	my @data = ();
+	while ( my $row = $rs_data->next ) {
+		push(
+			@data, {
+				"name"          => $row->name,
+				"description"	=> $row->description,
+				"lastUpdated" 	=> $row->last_updated
+			}
+		);
+	}
+	$self->success( \@data );
+}
+
+sub create {
+	my $self = shift;
+	my $params = $self->req->json;
+
+	if ( !&is_oper($self) ) {
+		return $self->forbidden();
+	}
+
+	if ( !defined($params) ) {
+		return $self->alert("Parameters must be in JSON format.");
+	}
+
+	my $name = $params->{name} if defined($params->{name});
+	my $description = $params->{description} if defined($params->{description});
+
+	if ( !defined($name) or $name eq "" ) {
+		return $self->alert( "Name is required." );
+	}
+
+	if ( !defined($description) or $description eq "" ) {
+		return $self->alert( "Description is required." );
+	}
+
+	# check if capability exists
+	my $rs_data = $self->db->resultset("Capability")->search( { 'name' => { 'like', $name } } )->single();
+	if (defined($rs_data)) {
+		return $self->alert( "Capability '$name' already exists." );
+	}
+
+	my $values = {
+		name		=> $name,
+		description	=> $description
+	};
+
+	my $insert = $self->db->resultset('Capability')->create($values);
+	my $rs = $insert->insert();
+	if ($rs) {
+		my $response;
+		$response->{name}			= $rs->name;
+		$response->{description}	= $rs->description;
+
+		&log( $self, "Created Capability: '$response->{name}', '$response->{description}'", "APICHANGE" );
+
+		return $self->success( $response, "Capability was created." );
+	}
+	else {
+		return $self->alert( "Capability creation failed." );
+	}
+}
+
+sub update {
+	my $self = shift;
+	my $name = $self->param('name');
+	my $params = $self->req->json;
+
+	if ( !&is_oper($self) ) {
+		return $self->forbidden();
+	}
+
+	if ( !defined($params) ) {
+		return $self->alert("Parameters must be in JSON format.");
+	}
+
+	my $description = $params->{description} if defined($params->{description});
+
+	my $capability = $self->db->resultset('Capability')->find( { name => $name } );
+	if ( !defined($capability) or $capability eq "" ) {
+		return $self->not_found();
+	}
+
+	if ( !defined($description) or $description eq "" ) {
+		return $self->alert( "Description is required." );
+	}
+
+	my $values = {
+		description => $description
+	};
+
+	my $rs = $capability->update($values);
+	if ($rs) {
+		my $response;
+		$response->{name}			= $rs->name;
+		$response->{description}	= $rs->description;
+		$response->{lastUpdated}	= $rs->last_updated;
+
+		&log( $self, "Updated Capability: '$response->{name}', '$response->{description}'", "APICHANGE" );
+
+		return $self->success( $response, "Capability was updated." );
+	}
+	else {
+		return $self->alert( "Capability update failed." );
+	}
+}
+
+sub delete {
+	my $self = shift;
+	my $name = $self->param('name');
+
+	if ( !&is_oper($self) ) {
+		return $self->forbidden();
+	}
+
+	my $capability = $self->db->resultset('Capability')->find( { name => $name } );
+	if ( !defined($capability) ) {
+		return $self->not_found();
+	}
+
+	# make sure no api_capability refers to this capability
+	my $rs_data = $self->db->resultset("ApiCapability")->find( {'me.capability' => $name} );
+	if (defined($rs_data)) {
+		my $reference_id = $rs_data->id;
+		return $self->alert( "Capability \'$name\' is refered by an api_capability mapping: $reference_id. Deletion failed." );
+	}
+
+	my $rs = $capability->delete();
+	if ($rs) {
+		return $self->success_message("Capability deleted.");
+	} else {
+		return $self->alert( "Capability deletion failed." );
+	}
+}
+
+1;

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/9546e8ad/traffic_ops/app/lib/TrafficOpsRoutes.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/TrafficOpsRoutes.pm b/traffic_ops/app/lib/TrafficOpsRoutes.pm
index ab6e5a7..e808b29 100644
--- a/traffic_ops/app/lib/TrafficOpsRoutes.pm
+++ b/traffic_ops/app/lib/TrafficOpsRoutes.pm
@@ -681,6 +681,23 @@ sub api_routes {
 	# Supports ?orderby=key
 	$r->get("/api/$version/roles")->over( authenticated => 1 )->to( 'Role#index', namespace => $namespace );
 
+	# -- CAPABILITIES
+	# Supports ?orderby=key
+	$r->get("/api/$version/capabilities")->over( authenticated => 1 )->to( 'Capability#all', namespace => $namespace );
+	$r->get("/api/$version/capabilities/:name")->over( authenticated => 1 )->to( 'Capability#name', namespace => $namespace );
+	$r->put("/api/$version/capabilities/:name")->over( authenticated => 1 )->to( 'Capability#update', namespace => $namespace );
+	$r->post("/api/$version/capabilities")->over( authenticated => 1 )->to( 'Capability#create', namespace => $namespace );
+	$r->delete("/api/$version/capabilities/:name")->over( authenticated => 1 )->to( 'Capability#delete', namespace => $namespace );
+
+	# -- API-CAPABILITIES
+	# Supports ?orderby=key
+	$r->get("/api/$version/api_capabilities")->over( authenticated => 1 )->to( 'ApiCapability#all', namespace => $namespace );
+	$r->get("/api/$version/api_capabilities/:id")->over( authenticated => 1 )->to( 'ApiCapability#index', namespace => $namespace );
+	$r->get("/api/$version/api_capabilities/capability/:name")->over( authenticated => 1 )->to( 'ApiCapability#capName', namespace => $namespace );
+	$r->put("/api/$version/api_capabilities/:id")->over( authenticated => 1 )->to( 'ApiCapability#update', namespace => $namespace );
+	$r->post("/api/$version/api_capabilities")->over( authenticated => 1 )->to( 'ApiCapability#create', namespace => $namespace );
+	$r->delete("/api/$version/api_capabilities/:id")->over( authenticated => 1 )->to( 'ApiCapability#delete', namespace => $namespace );
+
 	# -- SERVERS
 	# -- SERVERS: CRUD
 	$r->get("/api/$version/servers")->over( authenticated => 1 )->to( 'Server#index', namespace => $namespace );