You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by de...@apache.org on 2017/05/30 16:17:07 UTC

[2/2] incubator-trafficcontrol git commit: adds api to assign servers to a ds as well as fetch unassigned servers for a ds

adds api to assign servers to a ds as well as fetch unassigned servers for a ds


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

Branch: refs/heads/master
Commit: b21a4389ef0da936c1e54075999e2355a0f98284
Parents: 648d99e
Author: Jeremy Mitchell <mi...@gmail.com>
Authored: Tue May 23 20:30:36 2017 -0600
Committer: Dewayne Richardson <de...@apache.org>
Committed: Tue May 30 10:10:43 2017 -0600

----------------------------------------------------------------------
 .../traffic_ops_api/v12/deliveryservice.rst     | 213 ++++++++++++++++++-
 .../app/lib/API/DeliveryServiceServer.pm        |  39 ++++
 traffic_ops/app/lib/API/Server.pm               |  84 ++++++++
 traffic_ops/app/lib/Fixtures/Profile.pm         |  11 +
 traffic_ops/app/lib/Fixtures/Server.pm          |  70 ++++++
 traffic_ops/app/lib/TrafficOpsRoutes.pm         |   2 +
 traffic_ops/app/t/api/1.1/profile.t             |   6 +-
 traffic_ops/app/t/api/1.2/cachegroup.t          |   2 +-
 traffic_ops/app/t/api/1.2/deliveryservice.t     |  34 ++-
 traffic_ops/app/t/api/1.2/profile.t             |   6 +-
 traffic_ops/app/t/api/1.2/server.t              |   2 +-
 11 files changed, 450 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/docs/source/development/traffic_ops_api/v12/deliveryservice.rst
----------------------------------------------------------------------
diff --git a/docs/source/development/traffic_ops_api/v12/deliveryservice.rst b/docs/source/development/traffic_ops_api/v12/deliveryservice.rst
index 6c60e72..12bc0a5 100644
--- a/docs/source/development/traffic_ops_api/v12/deliveryservice.rst
+++ b/docs/source/development/traffic_ops_api/v12/deliveryservice.rst
@@ -487,11 +487,167 @@ Delivery Service
 
 **GET /api/1.2/deliveryservices/:id/servers**
 
-  Retrieves properties of CDN Edge servers assigned to a delivery service. Delivery service must be assigned to user if user is not admin or operations.
+  Retrieves properties of CDN EDGE or ORG servers assigned to a delivery service.
 
   Authentication Required: Yes
 
-  Role(s) Required: None
+  Role(s) Required: Admin or Operations or delivery service must be assigned to user.
+
+  **Request Route Parameters**
+
+  +-----------------+----------+---------------------------------------------------+
+  | Name            | Required | Description                                       |
+  +=================+==========+===================================================+
+  | ``id``          | yes      | Delivery service ID.                              |
+  +-----------------+----------+---------------------------------------------------+
+
+  **Response Properties**
+
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  |     Parameter      |  Type  |                                                Description                                                 |
+  +====================+========+============================================================================================================+
+  | ``cachegroup``     | string | The cache group name (see :ref:`to-api-v11-cachegroup`).                                                   |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``cachegroupId``   | string | The cache group id.                                                                                        |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``cdnId``          | string | Id of the CDN to which the server belongs to.                                                              |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``cdnName``        | string | Name of the CDN to which the server belongs to.                                                            |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``domainName``     | string | The domain name part of the FQDN of the cache.                                                             |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``guid``           | string | An identifier used to uniquely identify the server.                                                        |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``hostName``       | string | The host name part of the cache.                                                                           |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``httpsPort``      | string | The HTTPS port on which the main application listens (443 in most cases).                                  |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``id``             | string | The server id (database row number).                                                                       |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``iloIpAddress``   | string | The IPv4 address of the lights-out-management port.                                                        |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``iloIpGateway``   | string | The IPv4 gateway address of the lights-out-management port.                                                |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``iloIpNetmask``   | string | The IPv4 netmask of the lights-out-management port.                                                        |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``iloPassword``    | string | The password of the of the lights-out-management user (displays as ****** unless you are an 'admin' user). |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``iloUsername``    | string | The user name for lights-out-management.                                                                   |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``interfaceMtu``   | string | The Maximum Transmission Unit (MTU) to configure for ``interfaceName``.                                    |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``interfaceName``  | string | The network interface name used for serving traffic.                                                       |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``ip6Address``     | string | The IPv6 address/netmask for ``interfaceName``.                                                            |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``ip6Gateway``     | string | The IPv6 gateway for ``interfaceName``.                                                                    |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``ipAddress``      | string | The IPv4 address for ``interfaceName``.                                                                    |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``ipGateway``      | string | The IPv4 gateway for ``interfaceName``.                                                                    |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``ipNetmask``      | string | The IPv4 netmask for ``interfaceName``.                                                                    |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``lastUpdated``    | string | The Time and Date for the last update for this server.                                                     |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``mgmtIpAddress``  | string | The IPv4 address of the management port (optional).                                                        |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``mgmtIpGateway``  | string | The IPv4 gateway of the management port (optional).                                                        |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``mgmtIpNetmask``  | string | The IPv4 netmask of the management port (optional).                                                        |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``offlineReason``  | string | A user-entered reason why the server is in ADMIN_DOWN or OFFLINE status.                                   |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``physLocation``   | string | The physical location name (see :ref:`to-api-v11-phys-loc`).                                               |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``physLocationId`` | string | The physical location id (see :ref:`to-api-v11-phys-loc`).                                                 |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``profile``        | string | The assigned profile name (see :ref:`to-api-v11-profile`).                                                 |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``profileDesc``    | string | The assigned profile description (see :ref:`to-api-v11-profile`).                                          |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``profileId``      | string | The assigned profile Id (see :ref:`to-api-v11-profile`).                                                   |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``rack``           | string | A string indicating rack location.                                                                         |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``routerHostName`` | string | The human readable name of the router.                                                                     |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``routerPortName`` | string | The human readable name of the router port.                                                                |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``status``         | string | The Status string (See :ref:`to-api-v11-status`).                                                          |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``statusId``       | string | The Status id (See :ref:`to-api-v11-status`).                                                              |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``tcpPort``        | string | The default TCP port on which the main application listens (80 for a cache in most cases).                 |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``type``           | string | The name of the type of this server (see :ref:`to-api-v11-type`).                                          |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``typeId``         | string | The id of the type of this server (see :ref:`to-api-v11-type`).                                            |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+  | ``updPending``     |  bool  |                                                                                                            |
+  +--------------------+--------+------------------------------------------------------------------------------------------------------------+
+
+  **Response Example** ::
+
+   {
+      "response": [
+          {
+              "cachegroup": "us-il-chicago",
+              "cachegroupId": "3",
+              "cdnId": "3",
+              "cdnName": "CDN-1",
+              "domainName": "chi.kabletown.net",
+              "guid": null,
+              "hostName": "atsec-chi-00",
+              "id": "19",
+              "iloIpAddress": "172.16.2.6",
+              "iloIpGateway": "172.16.2.1",
+              "iloIpNetmask": "255.255.255.0",
+              "iloPassword": "********",
+              "iloUsername": "",
+              "interfaceMtu": "9000",
+              "interfaceName": "bond0",
+              "ip6Address": "2033:D0D0:3300::2:2/64",
+              "ip6Gateway": "2033:D0D0:3300::2:1",
+              "ipAddress": "10.10.2.2",
+              "ipGateway": "10.10.2.1",
+              "ipNetmask": "255.255.255.0",
+              "lastUpdated": "2015-03-08 15:57:32",
+              "mgmtIpAddress": "",
+              "mgmtIpGateway": "",
+              "mgmtIpNetmask": "",
+              "offlineReason": "N/A",
+              "physLocation": "plocation-chi-1",
+              "physLocationId": "9",
+              "profile": "EDGE1_CDN1_421_SSL",
+              "profileDesc": "EDGE1_CDN1_421_SSL profile",
+              "profileId": "12",
+              "rack": "RR 119.02",
+              "routerHostName": "rtr-chi.kabletown.net",
+              "routerPortName": "2",
+              "status": "ONLINE",
+              "statusId": "6",
+              "tcpPort": "80",
+              "httpsPort": "443",
+              "type": "EDGE",
+              "typeId": "3",
+              "updPending": false
+          },
+          {
+          ... more server data
+          }
+        ]
+    }
+
+|
+
+**GET /api/1.2/deliveryservices/:id/unassigned_servers**
+
+  Retrieves properties of CDN EDGE or ORG servers not assigned to a delivery service.
+
+  Authentication Required: Yes
+
+  Role(s) Required: Admin or Operations or delivery service must be assigned to user
 
   **Request Route Parameters**
 
@@ -855,7 +1011,7 @@ Health
 
 .. _to-api-v12-ds-server:
 
-Server
+Delivery Service Server
 ++++++
 
 **GET /api/1.2/deliveryserviceserver**
@@ -909,6 +1065,57 @@ Server
      "limit": 2
     }
 
+**POST /api/1.2/deliveryserviceserver**
+
+  Create one or more delivery service / server assignments.
+
+  Authentication Required: Yes
+
+  Role(s) Required: Admin or Operations or the delivery service is assigned to the user.
+
+  **Request Parameters**
+
+  +---------------------------------+----------+-------------------------------------------------------------------+
+  | Name                            | Required | Description                                                       |
+  +=================================+==========+===================================================================+
+  | ``dsId``                        | yes      | The ID of the delivery service.                                   |
+  +---------------------------------+----------+-------------------------------------------------------------------+
+  | ``servers``                     | yes      | An array of server IDs.                                           |
+  +---------------------------------+----------+-------------------------------------------------------------------+
+
+  **Request Example** ::
+
+    {
+        "dsId": 246,
+        "servers": [ 2, 3, 4, 5, 6 ]
+    }
+
+  **Response Properties**
+
+  +------------------------------------+--------+-------------------------------------------------------------------+
+  | Parameter                          | Type   | Description                                                       |
+  +====================================+========+===================================================================+
+  | ``dsId``                           | int    | The ID of the delivery service.                                   |
+  +------------------------------------+--------+-------------------------------------------------------------------+
+  | ``servers``                        | array  | An array of server IDs.                                           |
+  +------------------------------------+--------+-------------------------------------------------------------------+
+
+  **Response Example** ::
+
+    {
+        "alerts": [
+                  {
+                          "level": "success",
+                          "text": "Server assignments complete."
+                  }
+          ],
+        "response": {
+            "dsId" : 246,
+            "servers" : [ 2, 3, 4, 5, 6 ],
+        }
+    }
+
+|
 
 **DELETE /api/1.2/deliveryservice_server/:dsId/:serverId**
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/lib/API/DeliveryServiceServer.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/API/DeliveryServiceServer.pm b/traffic_ops/app/lib/API/DeliveryServiceServer.pm
index a75b5cc..1326267 100644
--- a/traffic_ops/app/lib/API/DeliveryServiceServer.pm
+++ b/traffic_ops/app/lib/API/DeliveryServiceServer.pm
@@ -68,6 +68,45 @@ sub domains {
 	$self->success( \@data );
 }
 
+sub create {
+	my $self 		= shift;
+	my $params 		= $self->req->json;
+	my $ds_id 		= $params->{dsId};
+	my $servers 	= $params->{servers};
+
+	if ( !&is_oper($self) ) {
+		return $self->forbidden();
+	}
+
+	if ( ref($servers) ne 'ARRAY' ) {
+		return $self->alert("Servers must be an array");
+	}
+
+	my $ds = $self->db->resultset('Deliveryservice')->find( { id => $ds_id } );
+	if ( !defined($ds) ) {
+		return $self->not_found();
+	}
+
+	$self->db->txn_begin();
+	foreach my $server (@{ $servers }) {
+		my $server_exist = $self->db->resultset('Server')->find( { id => $server } );
+		if ( !defined($server_exist) ) {
+			$self->db->txn_rollback();
+			return $self->alert("Server with id [ " . $server . " ] doesn't exist");
+		}
+		my $ds_server_exist = $self->db->resultset('DeliveryserviceServer')->find( { deliveryservice => $ds_id, server => $server } );
+		if ( !defined($ds_server_exist) ) {
+			$self->db->resultset('DeliveryserviceServer')->create( { deliveryservice => $ds_id, server => $server } )->insert();
+		}
+	}
+	$self->db->txn_commit();
+
+	&log( $self, "Servers were assigned to " . $ds->xml_id, "APICHANGE" );
+
+	my $response = $params;
+	return $self->success($response, "Server assignments complete.");
+}
+
 sub assign_ds_to_cachegroup {
 	my $self   = shift;
 	my $cg_id  = $self->param('id');

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/lib/API/Server.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/API/Server.pm b/traffic_ops/app/lib/API/Server.pm
index a593553..740c76d 100644
--- a/traffic_ops/app/lib/API/Server.pm
+++ b/traffic_ops/app/lib/API/Server.pm
@@ -556,6 +556,90 @@ sub get_edge_servers_by_dsid {
 	return $self->success( \@data );
 }
 
+sub get_unassigned_servers_by_dsid {
+	my $self    = shift;
+	my $ds_id   = $self->param('id');
+
+	my $ds = $self->db->resultset('Deliveryservice')->search( { id => $ds_id } )->single();
+	if ( !defined($ds) ) {
+		return $self->not_found();
+	}
+
+	my %ds_server_criteria;
+	$ds_server_criteria{'deliveryservice.id'} = $ds_id;
+
+	my @assigned_servers;
+	if ( &is_privileged($self) || $self->is_delivery_service_assigned($ds_id) ) {
+		@assigned_servers = $self->db->resultset('DeliveryserviceServer')->search( \%ds_server_criteria, { prefetch => [ 'deliveryservice', 'server' ] } )->get_column('server')->all();
+	}
+	else {
+		return $self->alert("Forbidden. Delivery service not assigned to user.");
+	}
+
+	my %server_criteria; # please fetch the following...
+	$server_criteria{'me.id'} = { 'not in' => \@assigned_servers }; # ...unassigned servers...
+	$server_criteria{'type.name'} = [ { -like => 'EDGE%' }, { -like => 'ORG' } ]; # ...of type EDGE% or ORG...
+	$server_criteria{'cdn.id'} = $ds->cdn_id; # ...that belongs to the same cdn as the ds...
+
+	my $servers = $self->db->resultset('Server')->search(
+		\%server_criteria,
+		{ prefetch => [ 'cdn', 'cachegroup', 'type', 'profile', 'status', 'phys_location' ] }
+	);
+
+	my @data;
+	if ( defined($servers) ) {
+		my $is_admin = &is_admin($self);
+		while ( my $row = $servers->next ) {
+			push(
+				@data, {
+					"cachegroup"     => $row->cachegroup->name,
+					"cachegroupId"   => $row->cachegroup->id,
+					"cdnId"          => $row->cdn->id,
+					"cdnName"        => $row->cdn->name,
+					"domainName"     => $row->domain_name,
+					"guid"           => $row->guid,
+					"hostName"       => $row->host_name,
+					"httpsPort"      => $row->https_port,
+					"id"             => $row->id,
+					"iloIpAddress"   => $row->ilo_ip_address,
+					"iloIpNetmask"   => $row->ilo_ip_netmask,
+					"iloIpGateway"   => $row->ilo_ip_gateway,
+					"iloUsername"    => $row->ilo_username,
+					"iloPassword"    => $is_admin ? $row->ilo_password : "",
+					"interfaceMtu"   => $row->interface_mtu,
+					"interfaceName"  => $row->interface_name,
+					"ip6Address"     => $row->ip6_address,
+					"ip6Gateway"     => $row->ip6_gateway,
+					"ipAddress"      => $row->ip_address,
+					"ipNetmask"      => $row->ip_netmask,
+					"ipGateway"      => $row->ip_gateway,
+					"lastUpdated"    => $row->last_updated,
+					"mgmtIpAddress"  => $row->mgmt_ip_address,
+					"mgmtIpNetmask"  => $row->mgmt_ip_netmask,
+					"mgmtIpGateway"  => $row->mgmt_ip_gateway,
+					"offlineReason"  => $row->offline_reason,
+					"physLocation"   => $row->phys_location->name,
+					"physLocationId" => $row->phys_location->id,
+					"profile"        => $row->profile->name,
+					"profileId"      => $row->profile->id,
+					"profileDesc"    => $row->profile->description,
+					"rack"           => $row->rack,
+					"routerHostName" => $row->router_host_name,
+					"routerPortName" => $row->router_port_name,
+					"status"         => $row->status->name,
+					"statusId"       => $row->status->id,
+					"tcpPort"        => $row->tcp_port,
+					"type"           => $row->type->name,
+					"typeId"         => $row->type->id,
+					"updPending"     => \$row->upd_pending
+				}
+			);
+		}
+	}
+
+	return $self->success( \@data );
+}
+
 sub get_servers_by_type {
 	my $self              = shift;
 	my $current_user      = shift;

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/lib/Fixtures/Profile.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/Fixtures/Profile.pm b/traffic_ops/app/lib/Fixtures/Profile.pm
index 4b021d2..7bcccc9 100644
--- a/traffic_ops/app/lib/Fixtures/Profile.pm
+++ b/traffic_ops/app/lib/Fixtures/Profile.pm
@@ -97,6 +97,17 @@ my %definition_for = (
 			type        => 'UNK_PROFILE',
 		},
 	},
+	EDGE2 => {
+		new   => 'Profile',
+		using => {
+			id          => 900,
+			name        => 'EDGE2',
+			description => 'edge description',
+			cdn         => 200,
+			type        => 'ATS_PROFILE',
+		},
+	},
+
 );
 
 sub get_definition {

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/lib/Fixtures/Server.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/Fixtures/Server.pm b/traffic_ops/app/lib/Fixtures/Server.pm
index a52ae69..ad535ca 100644
--- a/traffic_ops/app/lib/Fixtures/Server.pm
+++ b/traffic_ops/app/lib/Fixtures/Server.pm
@@ -543,6 +543,76 @@ my %definition_for = (
 			phys_location    => 100,
 		},
 	},
+	server_org1 => {
+		new   => 'Server',
+		using => {
+			id               => 1600,
+			host_name        => 'atlanta-org-1',
+			domain_name      => 'ga.atlanta.kabletown.net',
+			tcp_port         => 80,
+			xmpp_id          => 'atlanta-org-1\@ocdn.kabletown.net',
+			xmpp_passwd      => 'X',
+			interface_name   => 'bond0',
+			ip_address       => '127.0.0.17',
+			ip_netmask       => '255.255.255.252',
+			ip_gateway       => '127.0.0.17',
+			ip6_address      => '2345:1234:12:d::17/64',
+			ip6_gateway      => '2345:1234:12:d::1',
+			interface_mtu    => 9000,
+			rack             => 'RR 119.02',
+			mgmt_ip_address  => '',
+			mgmt_ip_netmask  => '',
+			mgmt_ip_gateway  => '',
+			ilo_ip_address   => '',
+			ilo_ip_netmask   => '',
+			ilo_ip_gateway   => '',
+			ilo_username     => '',
+			ilo_password     => '',
+			router_host_name => '',
+			router_port_name => '',
+			type             => 3,
+			status           => 2,
+			profile          => 100,
+			cdn_id           => 100,
+			cachegroup       => 800,
+			phys_location    => 100,
+		},
+	},
+	server_org2 => {
+		new   => 'Server',
+		using => {
+			id               => 1700,
+			host_name        => 'atlanta-org-2',
+			domain_name      => 'ga.atlanta.kabletown.net',
+			tcp_port         => 80,
+			xmpp_id          => 'atlanta-org-1\@ocdn.kabletown.net',
+			xmpp_passwd      => 'X',
+			interface_name   => 'bond0',
+			ip_address       => '127.0.0.18',
+			ip_netmask       => '255.255.255.252',
+			ip_gateway       => '127.0.0.18',
+			ip6_address      => '2345:1234:12:d::18/64',
+			ip6_gateway      => '2345:1234:12:d::1',
+			interface_mtu    => 9000,
+			rack             => 'RR 119.02',
+			mgmt_ip_address  => '',
+			mgmt_ip_netmask  => '',
+			mgmt_ip_gateway  => '',
+			ilo_ip_address   => '',
+			ilo_ip_netmask   => '',
+			ilo_ip_gateway   => '',
+			ilo_username     => '',
+			ilo_password     => '',
+			router_host_name => '',
+			router_port_name => '',
+			type             => 3,
+			status           => 2,
+			profile          => 900,
+			cdn_id           => 200,
+			cachegroup       => 800,
+			phys_location    => 100,
+		},
+	},
 );
 
 sub get_definition {

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/lib/TrafficOpsRoutes.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/TrafficOpsRoutes.pm b/traffic_ops/app/lib/TrafficOpsRoutes.pm
index 034edd9..4bcc514 100644
--- a/traffic_ops/app/lib/TrafficOpsRoutes.pm
+++ b/traffic_ops/app/lib/TrafficOpsRoutes.pm
@@ -572,6 +572,7 @@ sub api_routes {
 	# -- DELIVERYSERVICES: SERVERS
 	# Supports ?orderby=key
 	$r->get("/api/$version/deliveryserviceserver")->over( authenticated => 1 )->to( 'DeliveryServiceServer#index', namespace => $namespace );
+	$r->post("/api/$version/deliveryserviceserver")->over( authenticated => 1 )->to( 'DeliveryServiceServer#create', namespace => $namespace );
 
 	# -- DIVISIONS
 	$r->get("/api/$version/divisions")->over( authenticated => 1 )->to( 'Division#index', namespace => $namespace );
@@ -707,6 +708,7 @@ sub api_routes {
 
 	# get all edge servers associated with a delivery service (from deliveryservice_server table)
 	$r->get( "/api/$version/deliveryservices/:id/servers" => [ id => qr/\d+/ ] )->over( authenticated => 1 )->to( 'Server#get_edge_servers_by_dsid', namespace => $namespace );
+	$r->get( "/api/$version/deliveryservices/:id/unassigned_servers" => [ id => qr/\d+/ ] )->over( authenticated => 1 )->to( 'Server#get_unassigned_servers_by_dsid', namespace => $namespace );
 
 	# alternate server routes
 	$r->post("/api/$version/servers/create")->over( authenticated => 1 )->to( 'Server2#create', namespace => $namespace );

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/t/api/1.1/profile.t
----------------------------------------------------------------------
diff --git a/traffic_ops/app/t/api/1.1/profile.t b/traffic_ops/app/t/api/1.1/profile.t
index e9bb5fb..bfee6bf 100644
--- a/traffic_ops/app/t/api/1.1/profile.t
+++ b/traffic_ops/app/t/api/1.1/profile.t
@@ -43,9 +43,9 @@ $t->get_ok("/api/1.1/profiles.json?orderby=name")->status_is(200)->or( sub { dia
 	->json_is( "/response/0/name", "CCR1" )->json_is( "/response/0/description", "ccr description" )
 	->json_is( "/response/1/name", "CCR2" )->json_is( "/response/1/description", "ccr description" )
 	->json_is( "/response/2/name", "EDGE1" )->json_is( "/response/2/description", "edge description" )
-	->json_is( "/response/3/name", "MID1" )->json_is( "/response/3/description", "mid description" )
-	->json_is( "/response/4/name", "MISC" )->json_is( "/response/4/description", "misc profile description" )
-	->json_is( "/response/5/name", "RASCAL1" )->json_is( "/response/5/description", "rascal description" );
+	->json_is( "/response/3/name", "EDGE2" )->json_is( "/response/3/description", "edge description" )
+	->json_is( "/response/4/name", "MID1" )->json_is( "/response/4/description", "mid description" )
+	->json_is( "/response/5/name", "MISC" )->json_is( "/response/5/description", "misc profile description" );
 
 $t->get_ok("/api/1.1/profiles/trimmed.json")->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content}; } );
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/t/api/1.2/cachegroup.t
----------------------------------------------------------------------
diff --git a/traffic_ops/app/t/api/1.2/cachegroup.t b/traffic_ops/app/t/api/1.2/cachegroup.t
index 7bf5d34..5ef39a5 100644
--- a/traffic_ops/app/t/api/1.2/cachegroup.t
+++ b/traffic_ops/app/t/api/1.2/cachegroup.t
@@ -287,7 +287,7 @@ my $count_response = sub {
 $t->get_ok('/api/1.2/cachegroups/100/unassigned_parameters')->status_is(200)->$count_response(61)
     ->or( sub { diag $t->tx->res->content->asset->{content}; } );
 
-# there are currently 61 parameters not assigned to cachegroup 100
+# there are currently 61 parameters not assigned to cachegroup 200
 $t->get_ok('/api/1.2/cachegroups/200/unassigned_parameters')->status_is(200)->$count_response(61)
     ->or( sub { diag $t->tx->res->content->asset->{content}; } );
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/t/api/1.2/deliveryservice.t
----------------------------------------------------------------------
diff --git a/traffic_ops/app/t/api/1.2/deliveryservice.t b/traffic_ops/app/t/api/1.2/deliveryservice.t
index c5191f2..0f23e71 100644
--- a/traffic_ops/app/t/api/1.2/deliveryservice.t
+++ b/traffic_ops/app/t/api/1.2/deliveryservice.t
@@ -40,6 +40,32 @@ Test::TestHelper->load_core_data($schema);
 ok $t->post_ok( '/login', => form => { u => Test::TestHelper::ADMIN_USER, p => Test::TestHelper::ADMIN_USER_PASSWORD } )->status_is(302)
 	->or( sub { diag $t->tx->res->content->asset->{content}; } ), 'Should login?';
 
+# Count the 'response number'
+my $count_response = sub {
+	my ( $t, $count ) = @_;
+	my $json = decode_json( $t->tx->res->content->asset->slurp );
+	my $r    = $json->{response};
+	return $t->success( is( scalar(@$r), $count ) );
+};
+
+# there are currently 3 servers of type EDGE or ORG where server.cdn == ds.cdn not assigned to ds 100
+$t->get_ok('/api/1.2/deliveryservices/100/unassigned_servers')->status_is(200)->$count_response(4)
+	->or( sub { diag $t->tx->res->content->asset->{content}; } );
+
+# we will assign 2 more servers to ds 100
+ok $t->post_ok('/api/1.2/deliveryserviceserver' => {Accept => 'application/json'} => json => {
+			"dsId" => 100,
+			"servers" => [ 1400, 1600 ]
+		})
+		->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content}; } )
+		->json_is( "/alerts/0/level" => "success" )
+		->json_is( "/alerts/0/text" => "Server assignments complete." )
+	, 'Are the servers assigned to the delivery service?';
+
+# there are now 2 servers of type EDGE or ORG where server.cdn == ds.cdn not assigned to ds 100
+$t->get_ok('/api/1.2/deliveryservices/100/unassigned_servers')->status_is(200)->$count_response(2)
+	->or( sub { diag $t->tx->res->content->asset->{content}; } );
+
 # It gets existing delivery services
 ok $t->get_ok("/api/1.2/deliveryservices/list")->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content} } )
 		->json_is( "/response/0/xmlId", "steering-ds1" )
@@ -312,14 +338,6 @@ ok $t->get_ok("/api/1.2/deliveryservices.json")->status_is(200)->or( sub { diag
 	->json_is( "/response/0/xmlId", "ds_2" )->json_is( "/response/0/logsEnabled", 0 )->json_is( "/response/0/ipv6RoutingEnabled", 0 )
 	->json_is( "/response/1/xmlId", "ds_3" );
 
-# Count the 'response number'
-my $count_response = sub {
-	my ( $t, $count ) = @_;
-	my $json = decode_json( $t->tx->res->content->asset->slurp );
-	my $r    = $json->{response};
-	return $t->success( is( scalar(@$r), $count ) );
-};
-
 $t->get_ok('/api/1.2/deliveryservices/list?logsEnabled=true')->status_is(200)->$count_response(2)
 	->or( sub { diag $t->tx->res->content->asset->{content}; } );
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/t/api/1.2/profile.t
----------------------------------------------------------------------
diff --git a/traffic_ops/app/t/api/1.2/profile.t b/traffic_ops/app/t/api/1.2/profile.t
index 13d566f..37a2f2e 100644
--- a/traffic_ops/app/t/api/1.2/profile.t
+++ b/traffic_ops/app/t/api/1.2/profile.t
@@ -140,15 +140,15 @@ $t->get_ok('/api/1.2/profiles/200/unassigned_parameters')->status_is(200)->$coun
 	->or( sub { diag $t->tx->res->content->asset->{content}; } );
 
 # there are currently 7 profiles not assigned to parameter 4
-$t->get_ok('/api/1.2/parameters/4/unassigned_profiles')->status_is(200)->$count_response(7)
+$t->get_ok('/api/1.2/parameters/4/unassigned_profiles')->status_is(200)->$count_response(8)
 	->or( sub { diag $t->tx->res->content->asset->{content}; } );
 
 # there are currently 7 profiles not assigned to parameter 4
-$t->get_ok('/api/1.2/parameters/4/unassigned_profiles')->status_is(200)->$count_response(7)
+$t->get_ok('/api/1.2/parameters/4/unassigned_profiles')->status_is(200)->$count_response(8)
 	->or( sub { diag $t->tx->res->content->asset->{content}; } );
 
 # there are currently 6 profiles not assigned to parameter 6
-$t->get_ok('/api/1.2/parameters/6/unassigned_profiles')->status_is(200)->$count_response(6)
+$t->get_ok('/api/1.2/parameters/6/unassigned_profiles')->status_is(200)->$count_response(7)
 	->or( sub { diag $t->tx->res->content->asset->{content}; } );
 
 ok $t->get_ok('/logout')->status_is(302)->or( sub { diag $t->tx->res->content->asset->{content}; } );

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b21a4389/traffic_ops/app/t/api/1.2/server.t
----------------------------------------------------------------------
diff --git a/traffic_ops/app/t/api/1.2/server.t b/traffic_ops/app/t/api/1.2/server.t
index cedbfec..58ee930 100644
--- a/traffic_ops/app/t/api/1.2/server.t
+++ b/traffic_ops/app/t/api/1.2/server.t
@@ -527,7 +527,7 @@ ok $t->put_ok('/api/1.2/servers/' . $server_id => {Accept => 'application/json'}
 	, 'Does the server update succeed because ip6Address is already used by the profile but...by this server?';
 
 ok $t->get_ok('/api/1.2/servers/status')->status_is(200)->or( sub { diag $t->tx->res->content->asset->{content}; } )
-		->json_is( "/response/ONLINE", 15 )
+		->json_is( "/response/ONLINE", 17 )
 		->json_is( "/response/REPORTED", 5 )
 		->or( sub { diag $t->tx->res->content->asset->{content}; } );