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 25f95930d3 Added Traffic Portal page for CDNi config requests (#6639)
25f95930d3 is described below
commit 25f95930d3ea2aeca59eee1bffc4013226cee59a
Author: mattjackson220 <[email protected]>
AuthorDate: Wed Apr 20 16:14:04 2022 -0600
Added Traffic Portal page for CDNi config requests (#6639)
* Added Traffic Portal page for CDNi config requests
* updates per comments
* fixed spacing
* updated per comments
* updates per comments
* fixed docs
* fixed note spacing
---
CHANGELOG.md | 1 +
.../v4/oc_ci_configuration_request_id_approved.rst | 2 +-
.../source/api/v4/oc_ci_configuration_requests.rst | 96 ++++++++++++++++++++++
traffic_ops/traffic_ops_golang/cdni/shared.go | 86 ++++++++++++++++++-
traffic_ops/traffic_ops_golang/routing/routes.go | 5 +-
traffic_portal/app/src/app.js | 5 ++
traffic_portal/app/src/common/api/CdniService.js | 75 +++++++++++++++++
traffic_portal/app/src/common/api/index.js | 1 +
.../FormCdniRequestController.js | 50 +++++++++++
.../form.cdniConfigRequests.tpl.html | 53 ++++++++++++
.../modules/form/cdniConfigRequests/index.js | 21 +++++
.../common/modules/navigation/navigation.tpl.html | 1 +
.../cdniConfigRequests/TableCdniController.js | 68 +++++++++++++++
.../modules/table/cdniConfigRequests/index.js | 21 +++++
.../table.cdniConfigRequests.tpl.html | 23 ++++++
.../cdniConfigRequests/cdniConfigRequests.tpl.html | 22 +++++
.../modules/private/cdniConfigRequests/index.js | 34 ++++++++
.../private/cdniConfigRequests/list/index.js | 42 ++++++++++
.../private/cdniConfigRequests/view/index.js | 42 ++++++++++
19 files changed, 642 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 30e5270370..269a30baa5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- Added functionality for login to provide a Bearer token and for that token
to be later used for authorization.
- [Traffic Ops | Traffic Go Clients | T3C] Add additional timestamp fields to
server for queuing and dequeueing config and revalidate updates.
- Added layered profile feature to 4.0 for `GET` servers/, `POST` servers/,
`PUT` servers/{id} and `DELETE` servers/{id}.
+- Added a Traffic Ops endpoint and Traffic Portal page to view all CDNi
configuration update requests and approve or deny.
### Fixed
- Update traffic\_portal dependencies to mitigate `npm audit` issues.
diff --git a/docs/source/api/v4/oc_ci_configuration_request_id_approved.rst
b/docs/source/api/v4/oc_ci_configuration_request_id_approved.rst
index c709871572..7c4ab4cf71 100644
--- a/docs/source/api/v4/oc_ci_configuration_request_id_approved.rst
+++ b/docs/source/api/v4/oc_ci_configuration_request_id_approved.rst
@@ -25,7 +25,7 @@ Triggers an asynchronous task to update the configuration for
the :abbr:`uCDN (U
:Auth. Required: Yes
:Roles Required: "admin"
-:Permissions Required: CDNI-CAPACITY:ADMIN
+:Permissions Required: CDNI-ADMIN:READ, CDNI-ADMIN:UPDATE
:Response Type: Object
Request Structure
diff --git a/docs/source/api/v4/oc_ci_configuration_requests.rst
b/docs/source/api/v4/oc_ci_configuration_requests.rst
new file mode 100644
index 0000000000..cab8c5e20f
--- /dev/null
+++ b/docs/source/api/v4/oc_ci_configuration_requests.rst
@@ -0,0 +1,96 @@
+..
+..
+.. 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.
+..
+
+.. _to-api-oc-ci-configuration_requests:
+
+********************************
+``OC/CI/configuration/requests``
+********************************
+
+``GET``
+=======
+Returns the requested updates for :abbr:`CDNi (Content Delivery Network
Interconnect)` configurations. An optional ``id`` parameter will return only
information for a specific request.
+
+:Auth. Required: Yes
+:Roles Required: "admin"
+:Permissions Required: CDNI-ADMIN:READ
+:Response Type: Array
+
+Request Structure
+-----------------
+.. table:: Request Query Parameters
+
+
+-----------+----------+---------------------------------------------------------------------------------------------------------------+
+ | Name | Required | Description
|
+
+===========+==========+===============================================================================================================+
+ | id | no | Return only the configuration requests
identified by this integral, unique identifier |
+
+-----------+----------+---------------------------------------------------------------------------------------------------------------+
+
+Response Structure
+------------------
+:id: An integral, unique identifier for the requested
configuration updates.
+:ucdn: The name of the :abbr:`uCDN (Upstream Content
Delivery Network)` to which the requested changes apply.
+:data: An array of generic :abbr:`FCI (Footprint and
Capabilities Advertisement Interface)` base objects.
+:host: The domain to which the requested changes apply.
+:requestType: A string of the type of configuration update request.
+:asyncStatusId: An integral, unique identifier for the associated
asynchronous status.
+:generic-metadata-type: A string of the type of metadata to follow conforming
to :rfc:`8006`.
+:generic-metadata-value: An array of generic metadata value objects conforming
to :rfc:`8006` and :abbr:`SVA (Streaming Video Alliance)` specifications.
+:footprints: An array of footprints impacted by this generic base
object.
+
+.. note:: These are meant to be generic and therefore there is not much
information in these documents. For further information please see :rfc:`8006`,
:rfc:`8007`, :rfc:`8008`, and the :abbr:`SVA (Streaming Video Alliance)`
documents titled `Footprint and Capabilities Interface: Open Caching API`,
`Open Caching API Implementation Guidelines`, `Configuration Interface: Part 1
Specification - Overview & Architecture`, `Configuration Interface: Part 2
Specification – CDNi Metadata Model Ex [...]
+
+.. code-block:: json
+ :caption: Example /OC/CI/configuration/requests Response
+
+ {
+ "response": [
+ {
+ "id": 1,
+ "ucdn": "ucdn1",
+ "data": [
+ {
+ "generic-metadata-type":
"MI.RequestedCapacityLimits",
+ "generic-metadata-value": {
+ "requested-limits": [
+ {
+
"limit-type": "egress",
+
"limit-value": 232323,
+
"footprints": [
+
{
+
"footprint-type": "ipv4cidr",
+
"footprint-value": [
+
"127.0.0.1",
+
"127.0.0.2"
+
]
+
},
+
{
+
"footprint-type": "countrycode",
+
"footprint-value": [
+
"us"
+
]
+
}
+ ]
+ }
+ ]
+ }
+ }
+ ],
+ "host": "example.com",
+ "requestType": "hostConfigUpdate",
+ "asyncStatusId": 0
+ }
+ ]
+ }
diff --git a/traffic_ops/traffic_ops_golang/cdni/shared.go
b/traffic_ops/traffic_ops_golang/cdni/shared.go
index 75f7bccc4f..305d202576 100644
--- a/traffic_ops/traffic_ops_golang/cdni/shared.go
+++ b/traffic_ops/traffic_ops_golang/cdni/shared.go
@@ -56,8 +56,10 @@ LEFT JOIN cdni_telemetry as t ON telemetry_id = t.id
LEFT JOIN cdni_telemetry_metrics as tm ON telemetry_metric = tm.name
ORDER BY host DESC`
- InsertCapabilityUpdateQuery = `INSERT INTO
cdni_capability_updates (ucdn, data, async_status_id, request_type, host)
VALUES ($1, $2, $3, $4, $5)`
- SelectCapabilityUpdateQuery = `SELECT ucdn, data,
async_status_id, request_type, host FROM cdni_capability_updates WHERE id = $1`
+ InsertCapabilityUpdateQuery = `INSERT INTO cdni_capability_updates
(ucdn, data, async_status_id, request_type, host) VALUES ($1, $2, $3, $4, $5)`
+ SelectCapabilityUpdateQuery = `SELECT ucdn, data, async_status_id,
request_type, host FROM cdni_capability_updates WHERE id = $1`
+ SelectAllCapabilityUpdatesQuery = `SELECT id, ucdn, data, request_type,
host FROM cdni_capability_updates`
+
DeleteCapabilityUpdateQuery = `DELETE FROM
cdni_capability_updates WHERE id = $1`
UpdateTotalLimitsByCapabilityAndLimitTypeQuery = `UPDATE
cdni_total_limits SET maximum_hard = $1 WHERE capability_id = $2 AND limit_type
= $3`
UpdateHostLimitsByCapabilityAndLimitTypeQuery = `UPDATE
cdni_host_limits SET maximum_hard = $1 WHERE capability_id = $2 AND limit_type
= $3 AND host = $4`
@@ -66,6 +68,7 @@ ORDER BY host DESC`
hostConfigLabel = "hostConfigUpdate"
)
+// GetCapabilities returns the CDNi capability limits.
func GetCapabilities(w http.ResponseWriter, r *http.Request) {
inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
if userErr != nil || sysErr != nil {
@@ -127,6 +130,7 @@ func getBearerToken(r *http.Request) string {
return ""
}
+// PutHostConfiguration adds the requested CDNi configuration update for a
specific host to the queue and adds an async status.
func PutHostConfiguration(w http.ResponseWriter, r *http.Request) {
inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"host"}, nil)
if userErr != nil || sysErr != nil {
@@ -204,6 +208,7 @@ func PutHostConfiguration(w http.ResponseWriter, r
*http.Request) {
api.WriteAlerts(w, r, http.StatusAccepted, alerts)
}
+// PutConfiguration adds the requested CDNi configuration update to the queue
and adds an async status.
func PutConfiguration(w http.ResponseWriter, r *http.Request) {
inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
if userErr != nil || sysErr != nil {
@@ -274,6 +279,50 @@ func PutConfiguration(w http.ResponseWriter, r
*http.Request) {
api.WriteAlerts(w, r, http.StatusAccepted, alerts)
}
+// GetRequests returns the CDNi configuration update requests.
+func GetRequests(w http.ResponseWriter, r *http.Request) {
+ inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+
+ var rows *sql.Rows
+ var err error
+
+ idParam := inf.Params["id"]
+ if idParam != "" {
+ id, parseErr := strconv.Atoi(idParam)
+ if parseErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest,
errors.New("id must be an integer"), nil)
+ return
+ }
+ rows, err = inf.Tx.Tx.Query(SelectAllCapabilityUpdatesQuery+"
WHERE id = $1", id)
+ } else {
+ rows, err = inf.Tx.Tx.Query(SelectAllCapabilityUpdatesQuery)
+ }
+
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError,
nil, fmt.Errorf("querying for capability update requests: %w", err))
+ return
+ }
+ defer log.Close(rows, "closing capabilities update query")
+ requests := []ConfigurationUpdateRequest{}
+ for rows.Next() {
+ var request ConfigurationUpdateRequest
+ if err := rows.Scan(&request.ID, &request.UCDN, &request.Data,
&request.RequestType, &request.Host); err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx,
http.StatusInternalServerError, nil, fmt.Errorf("scanning db rows: %w", err))
+ return
+ }
+ requests = append(requests, request)
+ }
+
+ api.WriteResp(w, r, requests)
+
+}
+
+// PutConfigurationResponse approves or denies a CDNi configuration request
and updates the configuration and async status appropriately.
func PutConfigurationResponse(w http.ResponseWriter, r *http.Request) {
inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"approved",
"id"}, []string{"id"})
if userErr != nil || sysErr != nil {
@@ -510,7 +559,7 @@ func checkBearerToken(bearerToken string, inf *api.APIInfo)
(string, error) {
}
if token.Audience() == nil || len(token.Audience()) == 0 {
- return "", errors.New("invalid token - ucdn must be defined in
audience claim")
+ return "", errors.New("invalid token - dcdn must be defined in
audience claim")
}
if token.Audience()[0] != inf.Config.Cdni.DCdnId {
return "", errors.New("invalid token - incorrect dcdn")
@@ -634,26 +683,31 @@ func getTelemetryMetricsMap(tx *sql.Tx)
(map[string][]Metric, error) {
return telemetryMetricMap, nil
}
+// Capabilities contains an array of CDNi capabilities.
type Capabilities struct {
Capabilities []Capability `json:"capabilities"`
}
+// Capability contains information about a CDNi capability.
type Capability struct {
CapabilityType SupportedCapabilities `json:"capability-type"`
CapabilityValue interface{} `json:"capability-value"`
Footprints []Footprint `json:"footprints"`
}
+// CapacityCapabilityValue contains the total and host capability limits.
type CapacityCapabilityValue struct {
TotalLimits []Limit `json:"total-limits"`
HostLimits []HostLimit `json:"host-limits"`
}
+// HostLimit contains the capacity limit information for a specific host.
type HostLimit struct {
Host string `json:"host"`
Limits []Limit `json:"limits"`
}
+// Limit contains the information for a capacity limit.
type Limit struct {
LimitType CapacityLimitType `json:"limit-type"`
MaximumHard int64 `json:"maximum-hard"`
@@ -661,15 +715,18 @@ type Limit struct {
TelemetrySource TelemetrySource `json:"telemetry-source"`
}
+// TelemetrySource contains the information for a telemetry source.
type TelemetrySource struct {
Id string `json:"id"`
Metric string `json:"metric"`
}
+// TelemetryCapabilityValue contains an array of telemetry sources.
type TelemetryCapabilityValue struct {
Sources []Telemetry `json:"sources"`
}
+// Telemetry contains the information for a telemetry metric.
type Telemetry struct {
Id string `json:"id"`
Type TelemetrySourceType `json:"type"`
@@ -677,6 +734,7 @@ type Telemetry struct {
Metrics []Metric `json:"metrics"`
}
+// Metric contains the metric information for a telemetry metric.
type Metric struct {
Name string `json:"name"`
TimeGranularity int `json:"time-granularity"`
@@ -685,12 +743,14 @@ type Metric struct {
TelemetryId string `json:"-"`
}
+// Footprint contains the information for a footprint.
type Footprint struct {
FootprintType FootprintType `json:"footprint-type" db:"footprint_type"`
FootprintValue []string `json:"footprint-value"
db:"footprint_value"`
CapabilityId int `json:"-"`
}
+// CapacityLimitType is a string of the capacity limit type.
type CapacityLimitType string
const (
@@ -702,6 +762,7 @@ const (
CacheSize = "cache-size"
)
+// SupportedCapabilities is a string of the supported capabilities.
type SupportedCapabilities string
const (
@@ -709,6 +770,7 @@ const (
FciCapacityLimits = "FCI.CapacityLimits"
)
+// SupportedGenericMetadataType is a string of the supported metadata type.
type SupportedGenericMetadataType string
const (
@@ -723,12 +785,14 @@ func (s SupportedGenericMetadataType) isValid() bool {
return false
}
+// TelemetrySourceType is a string of the telemetry source type. Right now
only "generic" is supported.
type TelemetrySourceType string
const (
Generic TelemetrySourceType = "generic"
)
+// FootprintType is a string of the footprint type.
type FootprintType string
const (
@@ -738,32 +802,48 @@ const (
CountryCode = "countrycode"
)
+// GenericHostMetadata contains the generic CDNi metadata for a requested
update to a specific host.
type GenericHostMetadata struct {
Host string `json:"host"`
HostMetadata HostMetadataList `json:"host-metadata"`
}
+// GenericRequestMetadata contains the generic CDNi metadata for a requested
update.
type GenericRequestMetadata struct {
Type string `json:"type"`
Metadata json.RawMessage `json:"metadata"`
Host string `json:"host,omitempty"`
}
+// HostMetadataList contains CDNi metadata for a specific host.
type HostMetadataList struct {
Metadata json.RawMessage `json:"metadata"`
}
+// GenericMetadata contains generic CDNi metadata.
type GenericMetadata struct {
Type SupportedGenericMetadataType `json:"generic-metadata-type"`
Value json.RawMessage `json:"generic-metadata-value"`
}
+// CapacityRequestedLimits contains the requested capacity limits.
type CapacityRequestedLimits struct {
RequestedLimits []CapacityLimit `json:"requested-limits"`
}
+// CapacityLimit contains the limit information for a given footprint.
type CapacityLimit struct {
LimitType string `json:"limit-type"`
LimitValue int64 `json:"limit-value"`
Footprints []Footprint `json:"footprints"`
}
+
+// ConfigurationUpdateRequest contains information about a requested CDNi
configuration update request.
+type ConfigurationUpdateRequest struct {
+ ID int `json:"id"`
+ UCDN string `json:"ucdn"`
+ Data json.RawMessage `json:"data"`
+ Host string `json:"host"`
+ RequestType string `json:"requestType" db:"request_type"`
+ AsyncStatusID int `json:"asyncStatusId"
db:"async_status_id"`
+}
diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go
b/traffic_ops/traffic_ops_golang/routing/routes.go
index 149db14d06..cbfa250307 100644
--- a/traffic_ops/traffic_ops_golang/routing/routes.go
+++ b/traffic_ops/traffic_ops_golang/routing/routes.go
@@ -134,8 +134,9 @@ func Routes(d ServerData) ([]Route, http.Handler, error) {
// CDNI integration
{Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodGet, Path: `OC/FCI/advertisement/?$`, Handler: cdni.GetCapabilities,
RequiredPrivLevel: auth.PrivLevelReadOnly, RequiredPermissions:
[]string{"CDNI-CAPACITY:READ"}, Authenticated: Authenticated, Middlewares: nil,
ID: 541357729077},
{Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodPut, Path: `OC/CI/configuration/?$`, Handler: cdni.PutConfiguration,
RequiredPrivLevel: auth.PrivLevelReadOnly, RequiredPermissions:
[]string{"CDNI-CAPACITY:UPDATE"}, Authenticated: Authenticated, Middlewares:
nil, ID: 541357729078},
- {Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodPut, Path: `OC/CI/configuration/{host}?$`, Handler:
cdni.PutHostConfiguration, RequiredPrivLevel: auth.PrivLevelReadOnly,
RequiredPermissions: []string{"CDNI-CAPACITY:UPDATE"}, Authenticated:
Authenticated, Middlewares: nil, ID: 541357729079},
- {Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodPut, Path: `OC/CI/configuration/request/{id}/{approved}?$`, Handler:
cdni.PutConfigurationResponse, RequiredPrivLevel: auth.PrivLevelAdmin,
RequiredPermissions: []string{"CDNI-CAPACITY:ADMIN"}, Authenticated:
Authenticated, Middlewares: nil, ID: 541357729080},
+ {Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodPut, Path: `OC/CI/configuration/{host}$`, Handler:
cdni.PutHostConfiguration, RequiredPrivLevel: auth.PrivLevelReadOnly,
RequiredPermissions: []string{"CDNI-CAPACITY:UPDATE"}, Authenticated:
Authenticated, Middlewares: nil, ID: 541357729079},
+ {Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodPut, Path: `OC/CI/configuration/request/{id}/{approved}$`, Handler:
cdni.PutConfigurationResponse, RequiredPrivLevel: auth.PrivLevelAdmin,
RequiredPermissions: []string{"CDNI-ADMIN:READ", "CDNI-ADMIN:UPDATE"},
Authenticated: Authenticated, Middlewares: nil, ID: 541357729080},
+ {Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodGet, Path: `OC/CI/configuration/requests/?$`, Handler:
cdni.GetRequests, RequiredPrivLevel: auth.PrivLevelAdmin, RequiredPermissions:
[]string{"CDNI-ADMIN:READ"}, Authenticated: Authenticated, Middlewares: nil,
ID: 541357729081},
// SSL Keys
{Version: api.Version{Major: 4, Minor: 0}, Method:
http.MethodGet, Path: `sslkey_expirations/?$`, Handler:
deliveryservice.GetSSlKeyExpirationInformation, RequiredPrivLevel:
auth.PrivLevelAdmin, RequiredPermissions: []string{"SSL-KEY-EXPIRATION:READ"},
Authenticated: Authenticated, Middlewares: nil, ID: 41357729075},
diff --git a/traffic_portal/app/src/app.js b/traffic_portal/app/src/app.js
index 61b893f001..1e9b37bc66 100644
--- a/traffic_portal/app/src/app.js
+++ b/traffic_portal/app/src/app.js
@@ -212,6 +212,9 @@ var trafficPortal = angular.module('trafficPortal', [
require('./modules/private/tenants/users').name,
require('./modules/private/certExpirations').name,
require('./modules/private/certExpirations/list').name,
+ require('./modules/private/cdniConfigRequests').name,
+ require('./modules/private/cdniConfigRequests/list').name,
+ require('./modules/private/cdniConfigRequests/view').name,
require('./modules/private/types').name,
require('./modules/private/topologies').name,
require('./modules/private/topologies/cacheGroups').name,
@@ -277,6 +280,7 @@ var trafficPortal = angular.module('trafficPortal', [
require('./common/modules/form/cdn').name,
require('./common/modules/form/cdn/edit').name,
require('./common/modules/form/cdn/new').name,
+ require('./common/modules/form/cdniConfigRequests').name,
require('./common/modules/form/cdnDnssecKeys').name,
require('./common/modules/form/cdnDnssecKeys/generate').name,
require('./common/modules/form/cdnDnssecKeys/regenerateKsk').name,
@@ -373,6 +377,7 @@ var trafficPortal = angular.module('trafficPortal', [
require('./common/modules/table/cdnNotifications').name,
require('./common/modules/table/cdnServers').name,
require('./common/modules/table/certExpirations').name,
+ require('./common/modules/table/cdniConfigRequests').name,
require('./common/modules/table/coordinates').name,
require('./common/modules/table/deliveryServices').name,
require('./common/modules/table/deliveryServiceCapabilities').name,
diff --git a/traffic_portal/app/src/common/api/CdniService.js
b/traffic_portal/app/src/common/api/CdniService.js
new file mode 100644
index 0000000000..1d1e319b38
--- /dev/null
+++ b/traffic_portal/app/src/common/api/CdniService.js
@@ -0,0 +1,75 @@
+/*
+ * 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 CdniService = function($http, ENV, messageModel) {
+
+ this.getCdniConfigRequests = function() {
+ return $http.get(ENV.api.unstable +
'OC/CI/configuration/requests').then(
+ function (result) {
+ return result.data.response;
+ },
+ function (err) {
+ messageModel.setMessages(err.data.alerts, true);
+ throw err;
+ }
+ )
+ };
+
+ this.getCdniConfigRequestById = function(id) {
+ return $http.get(ENV.api.unstable +
'OC/CI/configuration/requests?id=' + id).then(
+ function (result) {
+ if (result.data.response.length > 0) {
+ return result.data.response[0]
+ }
+ return result.data.response;
+ },
+ function (err) {
+ messageModel.setMessages(err.data.alerts, true);
+ throw err;
+ }
+ )
+ };
+
+ this.getCurrentCdniConfigByUCDN = function(ucdn) {
+ return $http.get(ENV.api.unstable +
'OC/FCI/advertisement?ucdn=' + ucdn).then(
+ function (result) {
+ return result.data;
+ },
+ function (err) {
+ messageModel.setMessages(err.data.alerts, true);
+ throw err;
+ }
+ )
+ };
+
+ this.sendResponseToCdniRequest = function(id, approve) {
+ return $http.put(ENV.api.unstable +
'OC/CI/configuration/request/' + id + '/' + approve).then(
+ function (result) {
+ return result.data.response;
+ },
+ function (err) {
+ messageModel.setMessages(err.data.alerts, true);
+ throw err;
+ }
+ )
+ };
+};
+
+CdniService.$inject = ['$http', 'ENV', 'messageModel'];
+module.exports = CdniService;
diff --git a/traffic_portal/app/src/common/api/index.js
b/traffic_portal/app/src/common/api/index.js
index 66653d9e62..40f2220016 100644
--- a/traffic_portal/app/src/common/api/index.js
+++ b/traffic_portal/app/src/common/api/index.js
@@ -23,6 +23,7 @@ module.exports = angular.module('trafficPortal.api', [])
.service('cacheGroupService', require('./CacheGroupService'))
.service('cacheStatsService', require('./CacheStatsService'))
.service('capabilityService', require('./CapabilityService'))
+ .service('cdniService', require('./CdniService'))
.service('cdnService', require('./CDNService'))
.service('certExpirationsService', require('./CertExpirationsService'))
.service('changeLogService', require('./ChangeLogService'))
diff --git
a/traffic_portal/app/src/common/modules/form/cdniConfigRequests/FormCdniRequestController.js
b/traffic_portal/app/src/common/modules/form/cdniConfigRequests/FormCdniRequestController.js
new file mode 100644
index 0000000000..96397d4c68
--- /dev/null
+++
b/traffic_portal/app/src/common/modules/form/cdniConfigRequests/FormCdniRequestController.js
@@ -0,0 +1,50 @@
+/*
+ * 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 FormCdniRequestController = function($scope, $stateParams, $uibModal,
cdniService, cdniRequest, currentConfig, locationUtils, messageModel) {
+ $scope.reqId = $stateParams.reqId;
+ $scope.cdniRequest = cdniRequest;
+ $scope.cdniRequest.data = JSON.stringify($scope.cdniRequest.data, null,
5);
+ $scope.currentConfig = JSON.stringify(currentConfig, null, 5);
+
+ $scope.navigateToPath = locationUtils.navigateToPath;
+
+ $scope.respondToRequest = function(approve) {
+ const titleStart = approve ? 'Approve' : 'Deny';
+ const params = {
+ title: `${titleStart} CDNi Update Request:
${cdniRequest.id}`
+ };
+ const modalInstance = $uibModal.open({
+ templateUrl:
'common/modules/dialog/confirm/dialog.confirm.tpl.html',
+ controller: 'DialogConfirmController',
+ size: 'md',
+ resolve: {params}
+ });
+ modalInstance.result.then(function() {
+ cdniService.sendResponseToCdniRequest(cdniRequest.id,
approve).then(
+ function(result) {
+ messageModel.setMessages([{level:
'success', text: result}], true);
+
$scope.navigateToPath('/cdni-config-requests')
+ });
+ });
+ };
+};
+
+FormCdniRequestController.$inject = ['$scope', '$stateParams', '$uibModal',
'cdniService', 'cdniRequest', 'currentConfig', 'locationUtils', 'messageModel'];
+module.exports = FormCdniRequestController;
diff --git
a/traffic_portal/app/src/common/modules/form/cdniConfigRequests/form.cdniConfigRequests.tpl.html
b/traffic_portal/app/src/common/modules/form/cdniConfigRequests/form.cdniConfigRequests.tpl.html
new file mode 100644
index 0000000000..76a49e0e0a
--- /dev/null
+++
b/traffic_portal/app/src/common/modules/form/cdniConfigRequests/form.cdniConfigRequests.tpl.html
@@ -0,0 +1,53 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<div class="x_panel">
+ <div class="x_title">
+ <ol class="breadcrumb pull-left">
+ <li><a href="#!/cdni-config-requests">CDNi Requests</a></li>
+ <li class="active">{{reqId}}</li>
+ </ol>
+ <div class="clearfix"></div>
+ </div>
+ <div class="x_content">
+ <br>
+ <form name="cdniRequestForm" class="form-horizontal form-label-left"
novalidate>
+ <div class="form-group">
+ <label for="newData" class="control-label col-md-2 col-sm-2
col-xs-12">Updated Data</label>
+ <div class="col-md-10 col-sm-10 col-xs-12" style="padding-top:
10px">
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <textarea id="newData" name="newData" type="text"
class="form-control" ng-model="cdniRequest.data" rows="25" readonly></textarea>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="currentConfig" class="control-label col-md-2
col-sm-2 col-xs-12">Current Data</label>
+ <div class="col-md-10 col-sm-10 col-xs-12" style="padding-top:
10px">
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <textarea id="currentConfig" name="currentConfig"
type="text" class="form-control" ng-model="currentConfig" rows="25"
readonly></textarea>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-success"
ng-click="respondToRequest(true)">Approve</button>
+ <button type="button" class="btn btn-danger"
ng-click="respondToRequest(false)">Deny</button>
+ </div>
+ </form>
+ </div>
+</div>
diff --git
a/traffic_portal/app/src/common/modules/form/cdniConfigRequests/index.js
b/traffic_portal/app/src/common/modules/form/cdniConfigRequests/index.js
new file mode 100644
index 0000000000..eed0804538
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/form/cdniConfigRequests/index.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports = angular.module('trafficPortal.form.cdniConfigRequests', [])
+ .controller('FormCdniRequestController',
require('./FormCdniRequestController'));
diff --git
a/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
b/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
index 3234328924..d14e3e5a43 100644
--- a/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
+++ b/traffic_portal/app/src/common/modules/navigation/navigation.tpl.html
@@ -50,6 +50,7 @@ under the License.
<li class="side-menu-category-item"
ng-if="hasCapability('params-read')" ng-class="{'current-page':
isState('trafficPortal.private.parameters')}"><a
href="/#!/parameters">Parameters</a></li>
<li class="side-menu-category-item"
ng-if="hasCapability('types-read')" ng-class="{'current-page':
isState('trafficPortal.private.types')}"><a href="/#!/types">Types</a></li>
<li class="side-menu-category-item"
ng-if="hasCapability('statuses-read')" ng-class="{'current-page':
isState('trafficPortal.private.statuses')}"><a
href="/#!/statuses">Statuses</a></li>
+ <li class="side-menu-category-item"
ng-class="{'current-page':
isState('trafficPortal.private.cdniConfigRequests')}"><a
href="/#!/cdni-config-requests">CDNi Requests</a></li>
</ul>
</li>
<li class="side-menu-category"><a
href="javascript:void(0);"><i class="fa fa-sm fa-chevron-right"></i>
Topology</a>
diff --git
a/traffic_portal/app/src/common/modules/table/cdniConfigRequests/TableCdniController.js
b/traffic_portal/app/src/common/modules/table/cdniConfigRequests/TableCdniController.js
new file mode 100644
index 0000000000..06ffe6d85e
--- /dev/null
+++
b/traffic_portal/app/src/common/modules/table/cdniConfigRequests/TableCdniController.js
@@ -0,0 +1,68 @@
+/*
+ * 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 TableCdniController = function(tableName, cdniRequests, $scope,
locationUtils) {
+
+ $scope.cdniRequests = cdniRequests.map(
+ function(x) {
+ // need to convert this to a date object for ag-grid
filter to work properly
+ x.data = JSON.stringify(x.data);
+ return x;
+ });
+
+ /** The columns of the ag-grid table */
+ $scope.columns = [
+ {
+ headerName: "Upstream CDN",
+ field: "ucdn",
+ hide: false
+ },
+ {
+ headerName: "Host",
+ field: "host",
+ hide: false
+ },
+ {
+ headerName: "Request Type",
+ field: "request_type",
+ hide: false
+ },
+ {
+ headerName: "New Data",
+ field: "data",
+ hide: false
+ }
+ ];
+
+ /** Options, configuration, data and callbacks for the ag-grid table. */
+ $scope.gridOptions = {
+ onRowClick: function(params) {
+ const selection = window.getSelection().toString();
+ if(!selection) {
+
locationUtils.navigateToPath('/cdni-config-requests/' + params.data.id);
+ // Event is outside the digest cycle, so we
need to trigger one.
+ $scope.$apply();
+ }
+ }
+ };
+
+};
+
+TableCdniController.$inject = ['tableName', 'cdniRequests', '$scope',
'locationUtils'];
+module.exports = TableCdniController;
diff --git
a/traffic_portal/app/src/common/modules/table/cdniConfigRequests/index.js
b/traffic_portal/app/src/common/modules/table/cdniConfigRequests/index.js
new file mode 100644
index 0000000000..4b9a07aea5
--- /dev/null
+++ b/traffic_portal/app/src/common/modules/table/cdniConfigRequests/index.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports = angular.module('trafficPortal.table.cdniConfigRequests', [])
+ .controller('TableCdniController', require('./TableCdniController'));
diff --git
a/traffic_portal/app/src/common/modules/table/cdniConfigRequests/table.cdniConfigRequests.tpl.html
b/traffic_portal/app/src/common/modules/table/cdniConfigRequests/table.cdniConfigRequests.tpl.html
new file mode 100644
index 0000000000..a6d9baf194
--- /dev/null
+++
b/traffic_portal/app/src/common/modules/table/cdniConfigRequests/table.cdniConfigRequests.tpl.html
@@ -0,0 +1,23 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<div class="x_panel">
+ <common-grid-controller table-title="CDNi Update Requests"
table-name="cdniConfigRequests" options="gridOptions" data="cdniRequests"
+ columns="columns"></common-grid-controller>
+</div>
diff --git
a/traffic_portal/app/src/modules/private/cdniConfigRequests/cdniConfigRequests.tpl.html
b/traffic_portal/app/src/modules/private/cdniConfigRequests/cdniConfigRequests.tpl.html
new file mode 100644
index 0000000000..a71d5ff3dd
--- /dev/null
+++
b/traffic_portal/app/src/modules/private/cdniConfigRequests/cdniConfigRequests.tpl.html
@@ -0,0 +1,22 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<div id="cdniConfigRequestsContainer">
+ <div ui-view="cdniConfigRequestsContent"></div>
+</div>
diff --git a/traffic_portal/app/src/modules/private/cdniConfigRequests/index.js
b/traffic_portal/app/src/modules/private/cdniConfigRequests/index.js
new file mode 100644
index 0000000000..0bc0f2fc35
--- /dev/null
+++ b/traffic_portal/app/src/modules/private/cdniConfigRequests/index.js
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports = angular.module('trafficPortal.private.cdniConfigRequests', [])
+ .config(function($stateProvider, $urlRouterProvider) {
+ $stateProvider
+ .state('trafficPortal.private.cdniConfigRequests', {
+ url: 'cdni-config-requests',
+ abstract: true,
+ views: {
+ privateContent: {
+ templateUrl:
'modules/private/cdniConfigRequests/cdniConfigRequests.tpl.html'
+ }
+ }
+ })
+ ;
+ $urlRouterProvider.otherwise('/');
+ });
diff --git
a/traffic_portal/app/src/modules/private/cdniConfigRequests/list/index.js
b/traffic_portal/app/src/modules/private/cdniConfigRequests/list/index.js
new file mode 100644
index 0000000000..c321a63c01
--- /dev/null
+++ b/traffic_portal/app/src/modules/private/cdniConfigRequests/list/index.js
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports =
angular.module('trafficPortal.private.cdniConfigRequests.list', [])
+ .config(function($stateProvider, $urlRouterProvider) {
+ $stateProvider
+ .state('trafficPortal.private.cdniConfigRequests.list',
{
+ url: '',
+ views: {
+ cdniConfigRequestsContent: {
+ templateUrl:
'common/modules/table/cdniConfigRequests/table.cdniConfigRequests.tpl.html',
+ controller:
'TableCdniController',
+ resolve: {
+ cdniRequests:
function(cdniService) {
+ return
cdniService.getCdniConfigRequests();
+ },
+ tableName: function() {
+ return
'cdni-config-requests';
+ }
+ }
+ }
+ }
+ })
+ ;
+ $urlRouterProvider.otherwise('/');
+ });
diff --git
a/traffic_portal/app/src/modules/private/cdniConfigRequests/view/index.js
b/traffic_portal/app/src/modules/private/cdniConfigRequests/view/index.js
new file mode 100644
index 0000000000..42ff7b5ea9
--- /dev/null
+++ b/traffic_portal/app/src/modules/private/cdniConfigRequests/view/index.js
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+module.exports =
angular.module('trafficPortal.private.cdniConfigRequests.view', [])
+ .config(function($stateProvider, $urlRouterProvider) {
+ $stateProvider
+ .state('trafficPortal.private.cdniConfigRequests.view',
{
+ url: '/{reqId}',
+ views: {
+ cdniConfigRequestsContent: {
+ templateUrl:
'common/modules/form/cdniConfigRequests/form.cdniConfigRequests.tpl.html',
+ controller:
'FormCdniRequestController',
+ resolve: {
+ cdniRequest:
function($stateParams, cdniService) {
+ return
cdniService.getCdniConfigRequestById($stateParams.reqId);
+ },
+ currentConfig:
function(cdniRequest, cdniService) {
+ return
cdniService.getCurrentCdniConfigByUCDN(cdniRequest.ucdn);
+ }
+ }
+ }
+ }
+ })
+ ;
+ $urlRouterProvider.otherwise('/');
+ });