This is an automated email from the ASF dual-hosted git repository.
ocket8888 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new 9bfdfbd TO/TP: View servers by topology-based delivery service (#4966)
9bfdfbd is described below
commit 9bfdfbddb7a0c44cb85574fc62a3ee4de54982b3
Author: Zach Hoffman <[email protected]>
AuthorDate: Thu Sep 3 12:01:22 2020 -0600
TO/TP: View servers by topology-based delivery service (#4966)
* Query servers by the ID of a topology-based delivery service
* Add an API test
* Traffic Ops changelog entry
* [PATCH] Adds topology tests (zrhoffman/trafficcontrol#23)
* adds UI test for creating a topology
* adds UI test to view the servers for a ds that utilizes a topology
* adds changelog entry for TP
* Explain what servers will be returned when specifying dsId for a
topology-based delivery service
* Only allow querying servers by topology-based DS for API versions 3 and
up
* Term, not ref
* Use :dfn: text role
* Ensure version is not nil
* Keep using variadic useInTable
* Fix some warnings
- Name variables timestamp instead of time to avoid identifier collisions
- Use non-deprecated WithHdr() TO client functions
- Remove semicolon
- Remove parenthesis
* Version is not a pointer now
* adds the ability to view servers assigned to a ds that employs a topo…
(zrhoffman/trafficcontrol#25)
* adds the ability to view servers assigned to a ds that employs a topology
* only edges or orgs can be removed from a ds
* Nil check for ds.XMLID
* Do not rebind variable ds
* Assert that validation fails by looking for HTTP status code 400
* Use cachegroup3 in my-topology because cachegroup1 has lots of non-cache
servers
* Fix nil check logic
* fixes orderby in servers api and ds servers UI view
(zrhoffman/trafficcontrol#26)
* maintains the order of the servers as fetched from database
* orders ds servers by hostName
* Filter delivery service servers by CDN ID
* Filter by the delivery service's required capabilities
* Remove extra space
* adds a visual indicator that you are viewing ds servers as dictated by
the topology of the ds. (zrhoffman/trafficcontrol#28)
* changes font-size to medium (zrhoffman/trafficcontrol#29)
* Indent SQL
* Add space for RST table formatting
* Move HasRequiredCapabilitiesQuery to deliveryservice package
* Mention that only servers satisfying a DS's required capabilities are
returned for the dsId query parameter
Co-authored-by: Jeremy Mitchell <[email protected]>
---
CHANGELOG.md | 2 +
docs/source/api/v3/servers.rst | 6 +-
docs/source/glossary.rst | 8 ++
traffic_ops/testing/api/v3/servers_test.go | 89 +++++++++++++-------
traffic_ops/testing/api/v3/tc-fixtures.json | 2 +-
.../deliveryservices_required_capabilities.go | 9 ++
traffic_ops/traffic_ops_golang/server/servers.go | 96 +++++++++++++++++++---
.../traffic_ops_golang/server/servers_test.go | 8 +-
traffic_ops/v3-client/server.go | 1 +
traffic_ops/v3-client/type.go | 4 +-
.../form.deliveryService.DNS.tpl.html | 2 +-
.../form.deliveryService.HTTP.tpl.html | 2 +-
.../form.deliveryService.anyMap.tpl.html | 2 +-
.../modules/form/topology/form.topology.tpl.html | 2 +-
.../table.deliveryServiceServers.tpl.html | 4 +-
.../table/topologies/table.topologies.tpl.html | 2 +-
.../private/deliveryServices/servers/index.js | 6 +-
traffic_portal/app/src/styles/main.scss | 3 +
traffic_portal/test/end_to_end/conf.json | 1 +
.../deliveryServices/delivery-services-spec.js | 14 +++-
.../test/end_to_end/deliveryServices/pageData.js | 1 +
.../test/end_to_end/topologies/pageData.js | 27 ++++++
.../test/end_to_end/topologies/topologies-spec.js | 71 ++++++++++++++++
23 files changed, 303 insertions(+), 59 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fee8242..744e76c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- Traffic Ops: Added new `topology` field to the /api/3.0/deliveryservices
APIs
- Traffic Ops: Added support for `topology` query parameter to `GET
/api/3.0/cachegroups` to return all cachegroups used in the given topology.
- Traffic Ops: Added support for `topology` query parameter to `GET
/api/3.0/deliveryservices` to return all delivery services that employ a given
topology.
+ - Traffic Ops: Added support for `dsId` query parameter for `GET
/api/3.0/servers` for topology-based delivery services.
- Traffic Ops: Added new topology-based delivery service fields for header
rewrites: `firstHeaderRewrite`, `innerHeaderRewrite`, `lastHeaderRewrite`
- Traffic Ops: Added validation to prohibit assigning caches to
topology-based delivery services
- Traffic Ops: Consider Topologies parentage when queueing or checking
server updates
@@ -21,6 +22,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- Traffic Portal: Added the ability to assign topologies to delivery
services.
- Traffic Portal: Added the ability to view all delivery services and
cache groups associated with a topology.
- Traffic Portal: Added the ability to define first, inner and last header
rewrite values for DNS* and HTTP* delivery services that employ a topology.
+ - Traffic Portal: Adds the ability to view all servers utilized by a
topology-based delivery service.
- Traffic Portal: Added topology section to cdn snapshot diff.
- Traffic Router: Added support for topology-based delivery services
- Traffic Monitor: Added the ability to mark topology-based delivery
services as available
diff --git a/docs/source/api/v3/servers.rst b/docs/source/api/v3/servers.rst
index 27c9996..ac55750 100644
--- a/docs/source/api/v3/servers.rst
+++ b/docs/source/api/v3/servers.rst
@@ -36,7 +36,11 @@ Request Structure
+============+==========+===================================================================================================================+
| cachegroup | no | Return only those servers within the
:term:`Cache Group` that has this :ref:`cache-group-id` |
+------------+----------+-------------------------------------------------------------------------------------------------------------------+
- | dsId | no | Return only those servers assigned to the
:term:`Delivery Service` identified by this integral, unique identifier |
+ | dsId | no | Return only those servers assigned to the
:term:`Delivery Service` identified by this integral, unique identifier.|
+ | | | If the Delivery Service has a
:term:`Topology` assigned to it, the :ref:`to-api-servers` endpoint will return
|
+ | | | each server whose :term:`Cache Group` is
associated with a :term:`Topology Node` of that Topology and has the |
+ | | | :term:`Server Capabilities` that are
|
+ | | | :term:`required by the Delivery Service
<Delivery Service required capabilities>`. |
+------------+----------+-------------------------------------------------------------------------------------------------------------------+
| hostName | no | Return only those servers that have this
(short) hostname |
+------------+----------+-------------------------------------------------------------------------------------------------------------------+
diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst
index 0cf0493..75a8c51 100644
--- a/docs/source/glossary.rst
+++ b/docs/source/glossary.rst
@@ -422,6 +422,14 @@ Glossary
Tenancies
Users are grouped into :dfn:`Tenants` (or :dfn:`Tenancies`) to
segregate ownership of and permissions over :term:`Delivery Services` and their
resources. To be clear, the notion of :dfn:`Tenancy` **only** applies within
the context of :term:`Delivery Services` and does **not** apply permissions
restrictions to any other aspect of Traffic Control.
+ Topology Node
+ Topology Nodes
+ Parent Topology Node
+ Parent Topology Nodes
+ Child Topology Node
+ Child Topology Nodes
+ Each :dfn:`Topology Node` is associated with a particular
:term:`Cache Group`. In addition, the Topology Node has 0, 1, or 2 Parent
Topology Nodes and has 0, 1, or 2 Child Topology Nodes, according to your
configuration.
+
Topology
Topologies
A structure composed of :term:`Cache Groups` and parent
relationships, which is assignable to one or more :term:`Delivery Services`.
diff --git a/traffic_ops/testing/api/v3/servers_test.go
b/traffic_ops/testing/api/v3/servers_test.go
index a6bbe49..324e743 100644
--- a/traffic_ops/testing/api/v3/servers_test.go
+++ b/traffic_ops/testing/api/v3/servers_test.go
@@ -32,10 +32,10 @@ func TestServers(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Users, Parameters, Profiles,
Statuses, Divisions, Regions, PhysLocations, CacheGroups, Topologies,
DeliveryServices, Servers}, func() {
GetTestServersIMS(t)
currentTime := time.Now().UTC().Add(-5 * time.Second)
- time := currentTime.Format(time.RFC1123)
+ timestamp := currentTime.Format(time.RFC1123)
var header http.Header
header = make(map[string][]string)
- header.Set(rfc.IfModifiedSince, time)
+ header.Set(rfc.IfModifiedSince, timestamp)
UpdateTestServers(t)
GetTestServersDetails(t)
GetTestServers(t)
@@ -214,8 +214,8 @@ func GetTestServersIMS(t *testing.T) {
var header http.Header
header = make(map[string][]string)
futureTime := time.Now().AddDate(0, 0, 1)
- time := futureTime.Format(time.RFC1123)
- header.Set(rfc.IfModifiedSince, time)
+ timestamp := futureTime.Format(time.RFC1123)
+ header.Set(rfc.IfModifiedSince, timestamp)
params := url.Values{}
for _, server := range testData.Servers {
if server.HostName == nil {
@@ -256,7 +256,7 @@ func GetTestServers(t *testing.T) {
continue
}
params.Set("hostName", *server.HostName)
- resp, _, err := TOSession.GetServers(¶ms)
+ resp, _, err := TOSession.GetServersWithHdr(¶ms, nil)
if err != nil {
t.Errorf("cannot GET Server by name '%s': %v - %v",
*server.HostName, err, resp.Alerts)
} else if resp.Summary.Count != 1 {
@@ -272,7 +272,7 @@ func GetTestServersDetails(t *testing.T) {
t.Errorf("found server with nil hostname: %+v", server)
continue
}
- resp, _, err :=
TOSession.GetServerDetailsByHostName(*server.HostName)
+ resp, _, err :=
TOSession.GetServerDetailsByHostNameWithHdr(*server.HostName, nil)
if err != nil {
t.Errorf("cannot GET Server Details by name: %v - %v",
err, resp)
}
@@ -280,7 +280,7 @@ func GetTestServersDetails(t *testing.T) {
}
func GetTestServersQueryParameters(t *testing.T) {
- dses, _, err := TOSession.GetDeliveryServicesNullable()
+ dses, _, err := TOSession.GetDeliveryServicesNullableWithHdr(nil)
if err != nil {
t.Fatalf("Failed to get Delivery Services: %v", err)
}
@@ -295,24 +295,55 @@ func GetTestServersQueryParameters(t *testing.T) {
params := url.Values{}
params.Add("dsId", strconv.Itoa(*ds.ID))
- _, _, err = TOSession.GetServers(¶ms)
+ _, _, err = TOSession.GetServersWithHdr(¶ms, nil)
if err != nil {
t.Fatalf("Failed to get server by Delivery Service ID: %v", err)
}
currentTime := time.Now().UTC().Add(5 * time.Second)
- time := currentTime.Format(time.RFC1123)
+ timestamp := currentTime.Format(time.RFC1123)
var header http.Header
header = make(map[string][]string)
- header.Set(rfc.IfModifiedSince, time)
+ header.Set(rfc.IfModifiedSince, timestamp)
_, reqInf, _ := TOSession.GetServersWithHdr(¶ms, header)
if reqInf.StatusCode != http.StatusNotModified {
t.Errorf("Expected a status code of 304, got %v",
reqInf.StatusCode)
}
+ foundTopDs := false
+ const topDsXmlId = "ds-top"
+ for _, ds = range dses {
+ if ds.XMLID == nil || *ds.XMLID != topDsXmlId {
+ continue
+ }
+ foundTopDs = true
+ break
+ }
+ if !foundTopDs {
+ t.Fatalf("unable to find deliveryservice %s", topDsXmlId)
+ }
+ params.Set("dsId", strconv.Itoa(*ds.ID))
+ expectedHostnames := map[string]bool {
+ "edge1-cdn1-cg3": true,
+ "edge2-cdn1-cg3": true,
+ "atlanta-mid-16": true,
+ }
+ response, _, err := TOSession.GetServersWithHdr(¶ms, nil)
+ if err != nil {
+ t.Fatalf("Failed to get servers by Topology-based Delivery
Service ID with xmlId %s", err)
+ }
+ if len(response.Response) == 0 {
+ t.Fatalf("Did not find any servers for Topology-based Delivery
Service with xmlId %s", err)
+ }
+ for _, server := range response.Response {
+ if _, exists := expectedHostnames[*server.HostName]; !exists {
+ t.Fatalf("expected hostnames %v, actual %s actual: ",
expectedHostnames, *server.HostName)
+ }
+ }
+
params.Del("dsId")
- resp, _, err := TOSession.GetServers(nil)
+ resp, _, err := TOSession.GetServersWithHdr(nil, nil)
if err != nil {
t.Fatalf("Failed to get servers: %v", err)
}
@@ -324,7 +355,7 @@ func GetTestServersQueryParameters(t *testing.T) {
s := resp.Response[0]
params.Add("type", s.Type)
- if _, _, err := TOSession.GetServers(¶ms); err != nil {
+ if _, _, err := TOSession.GetServersWithHdr(¶ms, nil); err != nil {
t.Errorf("Error getting servers by type: %v", err)
}
params.Del("type")
@@ -333,7 +364,7 @@ func GetTestServersQueryParameters(t *testing.T) {
t.Error("Found server with no Cache Group ID")
} else {
params.Add("cachegroup", strconv.Itoa(*s.CachegroupID))
- if _, _, err := TOSession.GetServers(¶ms); err != nil {
+ if _, _, err := TOSession.GetServersWithHdr(¶ms, nil); err
!= nil {
t.Errorf("Error getting servers by Cache Group ID: %v",
err)
}
params.Del("cachegroup")
@@ -343,7 +374,7 @@ func GetTestServersQueryParameters(t *testing.T) {
t.Error("Found server with no status")
} else {
params.Add("status", *s.Status)
- if _, _, err := TOSession.GetServers(¶ms); err != nil {
+ if _, _, err := TOSession.GetServersWithHdr(¶ms, nil); err
!= nil {
t.Errorf("Error getting servers by status: %v", err)
}
params.Del("status")
@@ -353,13 +384,13 @@ func GetTestServersQueryParameters(t *testing.T) {
t.Error("Found server with no Profile ID")
} else {
params.Add("profileId", strconv.Itoa(*s.ProfileID))
- if _, _, err := TOSession.GetServers(¶ms); err != nil {
+ if _, _, err := TOSession.GetServersWithHdr(¶ms, nil); err
!= nil {
t.Errorf("Error getting servers by Profile ID: %v", err)
}
params.Del("profileId")
}
- cgs, _, err := TOSession.GetCacheGroupsNullable()
+ cgs, _, err := TOSession.GetCacheGroupsNullableWithHdr(nil)
if err != nil {
t.Fatalf("Failed to get Cache Groups: %v", err)
}
@@ -371,14 +402,14 @@ func GetTestServersQueryParameters(t *testing.T) {
}
params.Add("parentCacheGroup", strconv.Itoa(*cgs[0].ID))
- if _, _, err = TOSession.GetServers(¶ms); err != nil {
+ if _, _, err = TOSession.GetServersWithHdr(¶ms, nil); err != nil {
t.Errorf("Error getting servers by parentCacheGroup: %v", err)
}
params.Del("parentCacheGroup")
}
func UniqueIPProfileTestServers(t *testing.T) {
- serversResp, _, err := TOSession.GetServers(nil)
+ serversResp, _, err := TOSession.GetServersWithHdr(nil, nil)
if err != nil {
t.Fatal(err)
}
@@ -415,7 +446,7 @@ func UniqueIPProfileTestServers(t *testing.T) {
// Cleanup, don't want to break other tests
pathParams := url.Values{}
pathParams.Add("xmppid", xmppId)
- server, _, err := TOSession.GetServers(&pathParams)
+ server, _, err := TOSession.GetServersWithHdr(&pathParams, nil)
if err != nil {
t.Fatal(err)
}
@@ -460,7 +491,7 @@ func UpdateTestServers(t *testing.T) {
params.Add("hostName", hostName)
// Retrieve the server by hostname so we can get the id for the Update
- resp, _, err := TOSession.GetServers(¶ms)
+ resp, _, err := TOSession.GetServersWithHdr(¶ms, nil)
if err != nil {
t.Fatalf("cannot GET Server by hostname '%s': %v - %v",
hostName, err, resp.Alerts)
}
@@ -508,7 +539,7 @@ func UpdateTestServers(t *testing.T) {
}
// Retrieve the server to check rack, interfaceName, hostName values
were updated
- resp, _, err = TOSession.GetServers(&idParam)
+ resp, _, err = TOSession.GetServersWithHdr(&idParam, nil)
if err != nil {
t.Errorf("cannot GET Server by ID: %v - %v",
*remoteServer.HostName, err)
}
@@ -551,9 +582,9 @@ func UpdateTestServers(t *testing.T) {
//Check to verify XMPPID never gets updated
remoteServer.XMPPID = &updatedXMPPID
- al, _, err := TOSession.UpdateServerByID(*remoteServer.ID, remoteServer)
- if err != nil {
- t.Logf("cannot UPDATE Server by ID %d (hostname '%s'): %v -
%v", *remoteServer.ID, hostName, err, al)
+ al, reqInf, err := TOSession.UpdateServerByID(*remoteServer.ID,
remoteServer)
+ if err != nil && reqInf.StatusCode != http.StatusBadRequest {
+ t.Logf("error making sure that XMPPID does not get updated, %d
(hostname '%s'): %v - %v", *remoteServer.ID, hostName, err, al)
}
//Change back hostname and xmppid to its original name for other tests
to pass
@@ -563,13 +594,13 @@ func UpdateTestServers(t *testing.T) {
if err != nil {
t.Fatalf("cannot UPDATE Server by ID %d (hostname '%s'): %v -
%v", *remoteServer.ID, hostName, err, alert)
}
- resp, _, err = TOSession.GetServers(¶ms)
+ resp, _, err = TOSession.GetServersWithHdr(¶ms, nil)
if err != nil {
t.Errorf("cannot GET Server by hostName: %v - %v",
originalHostname, err)
}
// Assign server to DS and then attempt to update to a different type
- dses, _, err := TOSession.GetDeliveryServicesNullable()
+ dses, _, err := TOSession.GetDeliveryServicesNullableWithHdr(nil)
if err != nil {
t.Fatalf("cannot GET DeliveryServices: %v", err)
}
@@ -577,7 +608,7 @@ func UpdateTestServers(t *testing.T) {
t.Fatal("GET DeliveryServices returned no dses, must have at
least 1 to test invalid type server update")
}
- serverTypes, _, err := TOSession.GetTypes("server")
+ serverTypes, _, err := TOSession.GetTypesWithHdr(nil, "server")
if err != nil {
t.Fatalf("cannot GET Server Types: %v", err)
}
@@ -617,7 +648,7 @@ func DeleteTestServers(t *testing.T) {
params.Set("hostName", *server.HostName)
- resp, _, err := TOSession.GetServers(¶ms)
+ resp, _, err := TOSession.GetServersWithHdr(¶ms, nil)
if err != nil {
t.Errorf("cannot GET Server by hostname '%s': %v - %v",
*server.HostName, err, resp.Alerts)
continue
@@ -641,7 +672,7 @@ func DeleteTestServers(t *testing.T) {
}
// Retrieve the Server to see if it got deleted
- resp, _, err := TOSession.GetServers(¶ms)
+ resp, _, err := TOSession.GetServersWithHdr(¶ms,
nil)
if err != nil {
t.Errorf("error deleting Server hostname '%s':
%v - %v", *server.HostName, err, resp.Alerts)
}
diff --git a/traffic_ops/testing/api/v3/tc-fixtures.json
b/traffic_ops/testing/api/v3/tc-fixtures.json
index 7aad2ad..132497f 100644
--- a/traffic_ops/testing/api/v3/tc-fixtures.json
+++ b/traffic_ops/testing/api/v3/tc-fixtures.json
@@ -2763,7 +2763,7 @@
"parents": []
},
{
- "cachegroup": "cachegroup1",
+ "cachegroup": "cachegroup3",
"parents": [0, 1]
}
]
diff --git
a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go
b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go
index 9518e27..44333eb 100644
---
a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go
+++
b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go
@@ -423,3 +423,12 @@ deliveryservice_id) VALUES (
:required_capability,
:deliveryservice_id) RETURNING deliveryservice_id, required_capability,
last_updated`
}
+
+// language=SQL
+const HasRequiredCapabilitiesQuery = `
+SELECT EXISTS(
+ SELECT drc.required_capability
+ FROM deliveryservices_required_capability drc
+ WHERE drc.deliveryservice_id = $1
+)
+`
diff --git a/traffic_ops/traffic_ops_golang/server/servers.go
b/traffic_ops/traffic_ops_golang/server/servers.go
index 43bb78f..b33dd06 100644
--- a/traffic_ops/traffic_ops_golang/server/servers.go
+++ b/traffic_ops/traffic_ops_golang/server/servers.go
@@ -40,6 +40,7 @@ import (
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/routing/middleware"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/util/ims"
@@ -61,6 +62,43 @@ JOIN status st ON s.status = st.id
JOIN type t ON s.type = t.id
`
+/* language=SQL */
+const dssTopologiesJoinSubquery = `
+SELECT
+ td.id deliveryservice,
+ s.id "server"
+FROM "server" s
+JOIN cachegroup c on s.cachegroup = c.id
+LEFT JOIN topology_cachegroup tc ON c.name = tc.cachegroup
+LEFT JOIN deliveryservice td ON td.topology = tc.topology
+UNION
+`
+
+/* language=SQL */
+const deliveryServiceServersJoin = `
+FULL OUTER JOIN (
+%s
+SELECT
+ dss.deliveryservice,
+ dss."server"
+FROM deliveryservice_server dss
+) dss ON dss.server = s.id
+JOIN deliveryservice d ON cdn.id = d.cdn_id AND dss.deliveryservice = d.id
+`
+
+/* language=SQL */
+const requiredCapabilitiesCondition = `
+AND (
+ SELECT ARRAY_AGG(ssc.server_capability)
+ FROM server_server_capability ssc
+ WHERE ssc."server" = s.id
+) @> (
+ SELECT ARRAY_AGG(drc.required_capability)
+ FROM deliveryservices_required_capability drc
+ WHERE drc.deliveryservice_id = d.id
+)
+`
+
const serverCountQuery = `
SELECT COUNT(s.id)
` + serversFromAndJoin
@@ -609,7 +647,7 @@ func Read(w http.ResponseWriter, r *http.Request) {
log.Warnf("Couldn't get config %v", e)
}
- servers, serverCount, userErr, sysErr, errCode, maxTime =
getServers(r.Header, inf.Params, inf.Tx, inf.User, useIMS)
+ servers, serverCount, userErr, sysErr, errCode, maxTime =
getServers(r.Header, inf.Params, inf.Tx, inf.User, useIMS, *version)
if maxTime != nil {
// RFC1123
date := maxTime.Format("Mon, 02 Jan 2006 15:04:05 MST")
@@ -666,6 +704,13 @@ func ReadID(w http.ResponseWriter, r *http.Request) {
}
defer inf.Close()
+ // Middleware should've already handled this, so idk why this is a
pointer at all tbh
+ version := inf.Version
+ if version == nil {
+ middleware.NotImplementedHandler().ServeHTTP(w, r)
+ return
+ }
+
servers := []tc.ServerNullable{}
cfg, e := api.GetConfig(r.Context())
useIMS := false
@@ -674,7 +719,7 @@ func ReadID(w http.ResponseWriter, r *http.Request) {
} else {
log.Warnf("Couldn't get config %v", e)
}
- servers, _, userErr, sysErr, errCode, _ = getServers(r.Header,
inf.Params, inf.Tx, inf.User, useIMS)
+ servers, _, userErr, sysErr, errCode, _ = getServers(r.Header,
inf.Params, inf.Tx, inf.User, useIMS, *version)
if len(servers) > 1 {
api.HandleDeprecatedErr(w, r, tx,
http.StatusInternalServerError, nil, fmt.Errorf("ID '%d' matched more than one
server (%d total)", inf.IntParams["id"], len(servers)), &alternative)
return
@@ -713,7 +758,7 @@ JOIN type t ON s.type = t.id ` +
select max(last_updated) as t from last_deleted l where
l.table_name='server') as res`
}
-func getServers(h http.Header, params map[string]string, tx *sqlx.Tx, user
*auth.CurrentUser, useIMS bool) ([]tc.ServerNullable, uint64, error, error,
int, *time.Time) {
+func getServers(h http.Header, params map[string]string, tx *sqlx.Tx, user
*auth.CurrentUser, useIMS bool, version api.Version) ([]tc.ServerNullable,
uint64, error, error, int, *time.Time) {
var maxTime time.Time
var runSecond bool
// Query Parameters to Database Query column mappings
@@ -733,6 +778,7 @@ func getServers(h http.Header, params map[string]string, tx
*sqlx.Tx, user *auth
usesMids := false
queryAddition := ""
+ dsHasRequiredCapabilities := false
if dsIDStr, ok := params[`dsId`]; ok {
// don't allow query on ds outside user's tenant
dsID, err := strconv.Atoi(dsIDStr)
@@ -743,10 +789,20 @@ func getServers(h http.Header, params map[string]string,
tx *sqlx.Tx, user *auth
if userErr != nil || sysErr != nil {
return nil, 0, errors.New("Forbidden"), sysErr,
http.StatusForbidden, nil
}
+
+ var joinSubQuery string
+ if version.Major >= 3 {
+ if err =
tx.QueryRow(deliveryservice.HasRequiredCapabilitiesQuery,
dsID).Scan(&dsHasRequiredCapabilities); err != nil {
+ err = fmt.Errorf("unable to get required
capabilities for deliveryservice %d: %s", dsID, err)
+ return nil, 0, nil, err,
http.StatusInternalServerError, nil
+ }
+ joinSubQuery = dssTopologiesJoinSubquery
+ } else {
+ joinSubQuery = ""
+ }
// only if dsId is part of params: add join on
deliveryservice_server table
- queryAddition = `
- FULL OUTER JOIN deliveryservice_server dss ON
dss.server = s.id
- `
+ queryAddition = fmt.Sprintf(deliveryServiceServersJoin,
joinSubQuery)
+
// depending on ds type, also need to add mids
dsType, exists, err := dbhelpers.GetDeliveryServiceType(dsID,
tx.Tx)
if err != nil {
@@ -760,6 +816,9 @@ func getServers(h http.Header, params map[string]string, tx
*sqlx.Tx, user *auth
}
where, orderBy, pagination, queryValues, errs :=
dbhelpers.BuildWhereAndOrderByAndPagination(params, queryParamsToSQLCols)
+ if dsHasRequiredCapabilities {
+ where += requiredCapabilitiesCondition
+ }
if len(errs) > 0 {
return nil, 0, util.JoinErrs(errs), nil, http.StatusBadRequest,
nil
}
@@ -906,9 +965,10 @@ func getServers(h http.Header, params map[string]string,
tx *sqlx.Tx, user *auth
}
}
- returnable := make([]tc.ServerNullable, 0, len(servers))
- for _, server := range servers {
- for _, iface := range interfaces[*server.ID] {
+ returnable := make([]tc.ServerNullable, 0, len(ids))
+ for _, id := range ids {
+ server := servers[id]
+ for _, iface := range interfaces[id] {
server.Interfaces = append(server.Interfaces, iface)
}
returnable = append(returnable, server)
@@ -1089,8 +1149,15 @@ func Update(w http.ResponseWriter, r *http.Request) {
}
defer inf.Close()
+ // Middleware should've already handled this, so idk why this is a
pointer at all tbh
+ version := inf.Version
+ if version == nil {
+ middleware.NotImplementedHandler().ServeHTTP(w, r)
+ return
+ }
+
//Get original xmppid
- origSer, _, userErr, sysErr, _, _ := getServers(r.Header, inf.Params,
inf.Tx, inf.User, false)
+ origSer, _, userErr, sysErr, _, _ := getServers(r.Header, inf.Params,
inf.Tx, inf.User, false, *version)
if userErr != nil || sysErr != nil {
api.HandleErr(w, r, tx, errCode, userErr, sysErr)
return
@@ -1452,10 +1519,17 @@ func Delete(w http.ResponseWriter, r *http.Request) {
}
defer inf.Close()
+ // Middleware should've already handled this, so idk why this is a
pointer at all tbh
+ version := inf.Version
+ if version == nil {
+ middleware.NotImplementedHandler().ServeHTTP(w, r)
+ return
+ }
+
id := inf.IntParams["id"]
var servers []tc.ServerNullable
- servers, _, userErr, sysErr, errCode, _ = getServers(r.Header,
map[string]string{"id": inf.Params["id"]}, inf.Tx, inf.User, false)
+ servers, _, userErr, sysErr, errCode, _ = getServers(r.Header,
map[string]string{"id": inf.Params["id"]}, inf.Tx, inf.User, false, *version)
if userErr != nil || sysErr != nil {
api.HandleErr(w, r, tx, errCode, userErr, sysErr)
return
diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go
b/traffic_ops/traffic_ops_golang/server/servers_test.go
index aed94a7..5b00e20 100644
--- a/traffic_ops/traffic_ops_golang/server/servers_test.go
+++ b/traffic_ops/traffic_ops_golang/server/servers_test.go
@@ -27,6 +27,7 @@ import (
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/lib/go-util"
+ "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/test"
@@ -256,7 +257,9 @@ func TestGetServersByCachegroup(t *testing.T) {
user := auth.CurrentUser{}
- servers, _, userErr, sysErr, errCode, _ := getServers(nil, v,
db.MustBegin(), &user, false)
+ version := api.Version{Major: 3, Minor: 0}
+
+ servers, _, userErr, sysErr, errCode, _ := getServers(nil, v,
db.MustBegin(), &user, false, version)
if userErr != nil || sysErr != nil {
t.Errorf("getServers expected: no errors, actual: %v %v with
status: %s", userErr, sysErr, http.StatusText(errCode))
}
@@ -360,7 +363,8 @@ func TestGetMidServers(t *testing.T) {
v := map[string]string{}
user := auth.CurrentUser{}
- servers, _, userErr, sysErr, errCode, _ := getServers(nil, v,
db.MustBegin(), &user, false)
+ version := api.Version{Major: 3, Minor: 0}
+ servers, _, userErr, sysErr, errCode, _ := getServers(nil, v,
db.MustBegin(), &user, false, version)
if userErr != nil || sysErr != nil {
t.Errorf("getServers expected: no errors, actual: %v %v with
status: %s", userErr, sysErr, http.StatusText(errCode))
diff --git a/traffic_ops/v3-client/server.go b/traffic_ops/v3-client/server.go
index 2e2b8d8..dc71b1b 100644
--- a/traffic_ops/v3-client/server.go
+++ b/traffic_ops/v3-client/server.go
@@ -139,6 +139,7 @@ func (to *Session) UpdateServerByID(id int, server
tc.ServerNullable) (tc.Alerts
route := fmt.Sprintf("%s/%d", API_SERVERS, id)
resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody, nil)
reqInf.RemoteAddr = remoteAddr
+ reqInf.StatusCode = resp.StatusCode
if err != nil {
return alerts, reqInf, err
}
diff --git a/traffic_ops/v3-client/type.go b/traffic_ops/v3-client/type.go
index fe32257..ce1fdc1 100644
--- a/traffic_ops/v3-client/type.go
+++ b/traffic_ops/v3-client/type.go
@@ -72,7 +72,7 @@ func (to *Session) UpdateTypeByID(id int, typ tc.Type)
(tc.Alerts, ReqInf, error
// If a 'useInTable' parameter is passed, the returned Types are restricted to
those with
// that exact 'useInTable' property. Only exactly 1 or exactly 0 'useInTable'
parameters may
// be passed; passing more will result in an error being returned.
-func (to *Session) GetTypesWithHdr(header http.Header, useInTable []string)
([]tc.Type, ReqInf, error) {
+func (to *Session) GetTypesWithHdr(header http.Header, useInTable ...string)
([]tc.Type, ReqInf, error) {
if len(useInTable) > 1 {
return nil, ReqInf{}, errors.New("Please pass in a single value
for the 'useInTable' parameter")
}
@@ -114,7 +114,7 @@ func (to *Session) GetTypesWithHdr(header http.Header,
useInTable []string) ([]t
// 'useInTable' parameters may be passed; passing more will result in an error
being returned.
// Deprecated: GetTypes will be removed in 6.0. Use GetTypesWithHdr.
func (to *Session) GetTypes(useInTable ...string) ([]tc.Type, ReqInf, error) {
- return to.GetTypesWithHdr(nil, useInTable)
+ return to.GetTypesWithHdr(nil, useInTable...)
}
// GetTypeByID GETs a Type by the Type ID, and filters by http header params
in the request.
diff --git
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
index bc3e2ec..345044e 100644
---
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
+++
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
@@ -59,7 +59,7 @@ under the License.
<li role="menuitem"><a ng-click="viewOrigins()">Manage
Origins</a></li>
<li role="menuitem"><a ng-click="viewRegexes()">Manage
Regexes</a></li>
<li role="menuitem"><a
ng-click="viewCapabilities()">Manage Required Server Capabilities</a></li>
- <li ng-if="::(!deliveryService.topology)"
role="menuitem"><a ng-click="viewServers()">Manage Servers</a></li>
+ <li role="menuitem"><a ng-click="viewServers()">Manage
Servers</a></li>
<li role="menuitem"><a
ng-click="viewStaticDnsEntries()">Manage Static DNS Entries</a></li>
</ul>
</div>
diff --git
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
index 5ba80a3..fc0d626 100644
---
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
+++
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
@@ -59,7 +59,7 @@ under the License.
<li role="menuitem"><a ng-click="viewOrigins()">Manage
Origins</a></li>
<li role="menuitem"><a ng-click="viewRegexes()">Manage
Regexes</a></li>
<li role="menuitem"><a
ng-click="viewCapabilities()">Manage Required Server Capabilities</a></li>
- <li ng-if="::(!deliveryService.topology)"
role="menuitem"><a ng-click="viewServers()">Manage Servers</a></li>
+ <li role="menuitem"><a ng-click="viewServers()">Manage
Servers</a></li>
<li role="menuitem"><a
ng-click="viewStaticDnsEntries()">Manage Static DNS Entries</a></li>
</ul>
</div>
diff --git
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html
index e02acd8..7def518 100644
---
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html
+++
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.anyMap.tpl.html
@@ -51,7 +51,7 @@ under the License.
<hr class="divider"/>
<li role="menuitem"><a ng-click="viewCharts()">View
Charts</a></li>
<hr class="divider"/>
- <li ng-if="::(!deliveryService.topology)"
role="menuitem"><a ng-click="viewServers()">Manage Servers</a></li>
+ <li role="menuitem"><a ng-click="viewServers()">Manage
Servers</a></li>
</ul>
</div>
</div>
diff --git
a/traffic_portal/app/src/common/modules/form/topology/form.topology.tpl.html
b/traffic_portal/app/src/common/modules/form/topology/form.topology.tpl.html
index a1481e9..b2be7bf 100644
--- a/traffic_portal/app/src/common/modules/form/topology/form.topology.tpl.html
+++ b/traffic_portal/app/src/common/modules/form/topology/form.topology.tpl.html
@@ -87,7 +87,7 @@ under the License.
<a ng-if="node.cachegroup" title="View Servers Assigned to
{{::node.cachegroup}}" class="btn btn-primary btn-xs" data-nodrag
ng-click="viewCacheGroupServers(node)" style="margin-right: 8px;">
<i class="fa fa-server"></i>
</a>
- <a title="Add child cache groups to {{nodeLabel(node)}}"
class="btn btn-primary btn-xs" data-nodrag ng-click="addCacheGroups(node,
this)" style="margin-right: 8px;">
+ <a title="Add child cache groups to {{nodeLabel(node)}}"
class="btn btn-primary btn-xs add-child-cg-btn" data-nodrag
ng-click="addCacheGroups(node, this)" style="margin-right: 8px;">
<i class="fa fa-plus"></i>
</a>
<a ng-if="node.cachegroup" title="Remove {{::node.cachegroup}}
Cache Group" class="btn btn-danger btn-xs" data-nodrag
ng-click="deleteCacheGroup(node, this)">
diff --git
a/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
b/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
index c0ae775..e1d17db 100644
---
a/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
+++
b/traffic_portal/app/src/common/modules/table/deliveryServiceServers/table.deliveryServiceServers.tpl.html
@@ -22,7 +22,7 @@ under the License.
<ol class="breadcrumb pull-left">
<li><a href="#!/delivery-services">Delivery Services</a></li>
<li><a name="dsLink" ng-href="{{'#!/delivery-services/' +
deliveryService.id + '?type=' +
deliveryService.type}}">{{::deliveryService.xmlId}}</a></li>
- <li class="active">Servers</li>
+ <li class="active">Servers <small
ng-if="deliveryService.topology">[via {{deliveryService.topology}}
Topology]</small></li>
</ol>
<div class="pull-right">
<div class="form-inline" role="search">
@@ -76,7 +76,7 @@ under the License.
</li>
<hr class="divider"/>
<li role="menuitem">
- <button type="button" ng-click="confirmRemoveServer(server,
$event)" ng-disabled="deliveryService.topology">Remove Server from Delivery
Service</button>
+ <button type="button" ng-click="confirmRemoveServer(server,
$event)" ng-disabled="deliveryService.topology || (!isEdge(server) &&
!isOrigin(server))">Remove Server from Delivery Service</button>
</li>
<hr class="divider"/>
<li role="menuitem">
diff --git
a/traffic_portal/app/src/common/modules/table/topologies/table.topologies.tpl.html
b/traffic_portal/app/src/common/modules/table/topologies/table.topologies.tpl.html
index 1cf20b3..608e0a2 100644
---
a/traffic_portal/app/src/common/modules/table/topologies/table.topologies.tpl.html
+++
b/traffic_portal/app/src/common/modules/table/topologies/table.topologies.tpl.html
@@ -23,7 +23,7 @@ under the License.
<li class="active">Topologies</li>
</ol>
<div class="pull-right">
- <button type="button" class="btn btn-primary" title="Create
Topology" ng-click="createTopology()"><i class="fa fa-plus"></i></button>
+ <button type="button" name="createTopologyBtn" class="btn
btn-primary" title="Create Topology" ng-click="createTopology()"><i class="fa
fa-plus"></i></button>
<button type="button" class="btn btn-default" title="Refresh"
ng-click="refresh()"><i class="fa fa-refresh"></i></button>
</div>
<div class="clearfix"></div>
diff --git
a/traffic_portal/app/src/modules/private/deliveryServices/servers/index.js
b/traffic_portal/app/src/modules/private/deliveryServices/servers/index.js
index f54b518..db8bd6f 100644
--- a/traffic_portal/app/src/modules/private/deliveryServices/servers/index.js
+++ b/traffic_portal/app/src/modules/private/deliveryServices/servers/index.js
@@ -31,11 +31,7 @@ module.exports =
angular.module('trafficPortal.private.deliveryServices.servers'
return
deliveryServiceService.getDeliveryService($stateParams.deliveryServiceId);
},
servers:
function(deliveryService, $stateParams, serverService) {
- if
(deliveryService.topology) {
- return
serverService.getServers({ topology: deliveryService.topology });
- } else {
- return
serverService.getServers({ dsId: $stateParams.deliveryServiceId });
- }
+ return
serverService.getServers({ dsId: $stateParams.deliveryServiceId, orderby:
'hostName' });
},
filter: function() {
return null;
diff --git a/traffic_portal/app/src/styles/main.scss
b/traffic_portal/app/src/styles/main.scss
index 37dc352..e232b5c 100644
--- a/traffic_portal/app/src/styles/main.scss
+++ b/traffic_portal/app/src/styles/main.scss
@@ -138,6 +138,9 @@ body.nav-sm .container.body .main-content {
background-color: white;
border-radius: 0;
font-size: 24px;
+ small {
+ font-size: medium;
+ }
}
.input-group-addon > label {
diff --git a/traffic_portal/test/end_to_end/conf.json
b/traffic_portal/test/end_to_end/conf.json
index aa1ecb6..6cf787a 100644
--- a/traffic_portal/test/end_to_end/conf.json
+++ b/traffic_portal/test/end_to_end/conf.json
@@ -19,6 +19,7 @@
"login/login-spec.js",
"CDNs/cdns-spec.js",
"cacheGroups/cache-groups-spec.js",
+ "topologies/topologies-spec.js",
"profiles/profiles-spec.js",
"divisions/divisions-spec.js",
"regions/regions-spec.js",
diff --git
a/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
b/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
index 6b9281e..100f112 100644
--- a/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
+++ b/traffic_portal/test/end_to_end/deliveryServices/delivery-services-spec.js
@@ -264,7 +264,7 @@ describe('Traffic Portal Delivery Services Suite',
function() {
});
it('should populate and submit the delivery service form', function() {
- console.log('Creating a HTTP DS for ' + mockVals.dnsXmlId);
+ console.log('Creating a HTTP DS with a topology for ' +
mockVals.httpXmlId);
expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services/new?type=HTTP");
expect(pageData.createButton.isEnabled()).toBe(false);
// set required fields
@@ -288,6 +288,8 @@ describe('Traffic Portal Delivery Services Suite',
function() {
commonFunctions.selectDropdownbyNum(pageData.protocol, 1);
// all required fields have been set, create button should be
enabled
expect(pageData.createButton.isEnabled()).toBe(true);
+ // set topology
+ commonFunctions.selectDropdownbyNum(pageData.topology, 1);
pageData.createButton.click();
});
@@ -355,6 +357,16 @@ describe('Traffic Portal Delivery Services Suite',
function() {
});
});
+ it('should navigate back to the HTTP delivery service and view all
servers utilized per the assigned topology', function() {
+ console.log('Viewing all servers utilized by ' +
mockVals.httpXmlId);
+ pageData.dsLink.click();
+ pageData.moreBtn.click();
+ pageData.manageServersMenuItem.click();
+
expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toMatch(commonFunctions.urlPath(browser.baseUrl)+"#!/delivery-services/[0-9]+/servers");
+ console.log('The ability to assign servers is disabled for ' +
mockVals.httpXmlId);
+ expect(pageData.selectServersBtn.isEnabled()).toBe(false);
+ });
+
it('should navigate back to the HTTP delivery service and delete it',
function() {
console.log('Deleting ' + mockVals.httpXmlId);
pageData.dsLink.click();
diff --git a/traffic_portal/test/end_to_end/deliveryServices/pageData.js
b/traffic_portal/test/end_to_end/deliveryServices/pageData.js
index d30ef04..f17a010 100644
--- a/traffic_portal/test/end_to_end/deliveryServices/pageData.js
+++ b/traffic_portal/test/end_to_end/deliveryServices/pageData.js
@@ -35,6 +35,7 @@ module.exports = function(){
this.cdn=element(by.name('cdn'));
this.orgServerFqdn=element(by.name('orgServerFqdn'));
this.protocol=element(by.name('protocol'));
+ this.topology=element(by.name('topology'));
this.longDesc=element(by.name('longDesc'));
this.remapText=element(by.name('remapText'));
this.createButton=element(by.buttonText('Create'));
diff --git a/traffic_portal/test/end_to_end/topologies/pageData.js
b/traffic_portal/test/end_to_end/topologies/pageData.js
new file mode 100644
index 0000000..043ec8f
--- /dev/null
+++ b/traffic_portal/test/end_to_end/topologies/pageData.js
@@ -0,0 +1,27 @@
+/*
+ * 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 = function(){
+ this.name=element(by.name('name'));
+ this.description=element(by.id('description'));
+ this.addChildCacheGroupBtn=element(by.css('.add-child-cg-btn'));
+ this.selectFormSubmitButton=element(by.buttonText('Submit'));
+ this.selectAllCB=element(by.id('selectAllCB'));
+ this.createButton=element(by.buttonText('Create'));
+};
diff --git a/traffic_portal/test/end_to_end/topologies/topologies-spec.js
b/traffic_portal/test/end_to_end/topologies/topologies-spec.js
new file mode 100644
index 0000000..ec0987a
--- /dev/null
+++ b/traffic_portal/test/end_to_end/topologies/topologies-spec.js
@@ -0,0 +1,71 @@
+/*
+ * 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 pd = require('./pageData.js');
+var cfunc = require('../common/commonFunctions.js');
+
+describe('Traffic Portal Topologies Test Suite', function() {
+ const pageData = new pd();
+ const commonFunctions = new cfunc();
+ const ec = protractor.ExpectedConditions;
+ const myNewTopology = {
+ name: 'topology-' +
commonFunctions.shuffle('abcdefghijklmonpqrstuvwxyz0123456789'),
+ desc: 'topology-' +
commonFunctions.shuffle('abcdefghijklmonpqrstuvwxyz0123456789')
+ };
+
+ it('should go to the topologies page', function() {
+ console.log("Go to the topologies page");
+ browser.setLocation("topologies");
+
expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/topologies");
+ });
+
+ it('should verify CSV link exists ', function() {
+ console.log("Verify CSV button exists");
+
expect(element(by.css('.dt-button.buttons-csv')).isPresent()).toBe(true);
+ });
+
+ it('should open new topology form page', function() {
+ console.log("Open new topology form page");
+
browser.driver.findElement(by.name('createTopologyBtn')).click();
+
expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/topologies/new");
+ });
+
+ it('should build a new topology', function () {
+ console.log("Building a new topology");
+ pageData.addChildCacheGroupBtn.click();
+ expect(pageData.selectFormSubmitButton.isEnabled()).toBe(false);
+
browser.driver.findElement(by.name('selectFormDropdown')).sendKeys('EDGE_LOC');
+ expect(pageData.selectFormSubmitButton.isEnabled()).toBe(true);
+ pageData.selectFormSubmitButton.click();
+ browser.wait(ec.presenceOf(pageData.selectAllCB), 5000);
+ pageData.selectAllCB.click();
+ pageData.selectFormSubmitButton.click();
+ });
+
+ it('should fill out the rest of the topology form, create button is
enabled and submit', function () {
+ console.log("Filling out topology form, check create button is
enabled and submit");
+ expect(pageData.createButton.isEnabled()).toBe(false);
+ pageData.name.sendKeys(myNewTopology.name);
+ pageData.description.sendKeys(myNewTopology.desc);
+ expect(pageData.createButton.isEnabled()).toBe(true);
+ pageData.createButton.click();
+
expect(browser.getCurrentUrl().then(commonFunctions.urlPath)).toEqual(commonFunctions.urlPath(browser.baseUrl)+"#!/topologies");
+ });
+
+});