This is an automated email from the ASF dual-hosted git repository.

rawlin 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 15101a5  URL Sig Keys in Postgres and DELETE methods (#5801)
15101a5 is described below

commit 15101a5bb7e7edf19f1bfc8c30848444c44d1fde
Author: mattjackson220 <[email protected]>
AuthorDate: Tue May 4 09:54:41 2021 -0600

    URL Sig Keys in Postgres and DELETE methods (#5801)
    
    * URL Sig Keys in Postgres and DELETE methods
    
    * updated per comments
    
    * return error for delete
    
    * added API doc for new DELETE
    
    * fixed copy error
    
    * added Changelog entry for URL sign key delete
---
 CHANGELOG.md                                       |   1 +
 docs/source/api/v4/deliveryservices_id_urlkeys.rst |  33 +++++++
 .../v4/deliveryservices_xmlid_xmlid_urlkeys.rst    |  33 +++++++
 .../testing/api/v4/deliveryservices_test.go        |  59 +++++++++++
 .../traffic_ops_golang/deliveryservice/urlkey.go   | 109 +++++++++++++++++++++
 traffic_ops/traffic_ops_golang/routing/routes.go   |   2 +
 .../trafficvault/backends/disabled/disabled.go     |   4 +
 .../trafficvault/backends/postgres/postgres.go     |  25 ++++-
 .../trafficvault/backends/postgres/url_sig_keys.go |  82 ++++++++++++++++
 .../trafficvault/backends/riaksvc/dsutil.go        |  12 +++
 .../trafficvault/backends/riaksvc/riak.go          |   4 +
 .../trafficvault/trafficvault.go                   |   3 +
 traffic_ops/v4-client/deliveryservice.go           |  22 +++++
 13 files changed, 387 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d38e85d..e82b7ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,7 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 - Add a Federation to the Ansible Dataset Loader
 - Added asynchronous status to ACME certificate generation.
 - Added headers to Traffic Portal, Traffic Ops, and Traffic Monitor to opt out 
of tracking users via Google FLoC.
+- `DELETE` request method for `deliveryservices/xmlId/{name}/urlkeys` and 
`deliveryservices/{id}/urlkeys`.
 
 ### Fixed
 - [#5690](https://github.com/apache/trafficcontrol/issues/5690) - Fixed github 
action for added/modified db migration file.
diff --git a/docs/source/api/v4/deliveryservices_id_urlkeys.rst 
b/docs/source/api/v4/deliveryservices_id_urlkeys.rst
index 3fa07ea..e5e42b4 100644
--- a/docs/source/api/v4/deliveryservices_id_urlkeys.rst
+++ b/docs/source/api/v4/deliveryservices_id_urlkeys.rst
@@ -91,3 +91,36 @@ Response Structure
                        "key15": "...",
                }
        }
+
+
+``DELETE``
+==========
+.. seealso:: :ref:`to-api-deliveryservices-xmlid-xmlid-urlkeys`
+
+Deletes URL signing keys for a :term:`Delivery Service`.
+
+:Auth. Required: Yes
+:Roles Required: "admin" or "operations"
+:Response Type:  Object
+
+Request Structure
+-----------------
+.. table:: Request Path Parameters
+
+       
+------+----------------------------------------------------------------------------------------+
+       | Name | Description                                                    
                        |
+       
+======+========================================================================================+
+       | id   | Filter for the :term:`Delivery Service` identified by this 
integral, unique identifier |
+       
+------+----------------------------------------------------------------------------------------+
+
+Response Structure
+------------------
+.. code-block:: json
+       :caption: Response Example
+
+       {
+               "alerts": [{
+                       "level": "success",
+                       "text": "Successfully deleted URL Sig keys from Traffic 
Vault"
+               }]
+       }
diff --git a/docs/source/api/v4/deliveryservices_xmlid_xmlid_urlkeys.rst 
b/docs/source/api/v4/deliveryservices_xmlid_xmlid_urlkeys.rst
index f50aee9..03dca83 100644
--- a/docs/source/api/v4/deliveryservices_xmlid_xmlid_urlkeys.rst
+++ b/docs/source/api/v4/deliveryservices_xmlid_xmlid_urlkeys.rst
@@ -66,3 +66,36 @@ Response Structure
                "key14":"DtXsu8nsw04YhT0kNoKBhu2G3P9WRpQJ",
                "key7":"cmKoIIxXGAxUMdCsWvnGLoIMGmNiuT5I"
        }}
+
+
+``DELETE``
+==========
+.. seealso:: :ref:`to-api-deliveryservices-id-urlkeys`
+
+Deletes URL signing keys for a :term:`Delivery Service`.
+
+:Auth. Required: Yes
+:Roles Required: "admin" or "operations"
+:Response Type:  Object
+
+Request Structure
+-----------------
+.. table:: Request Path Parameters
+
+       +-------+------------------------------------------------------+
+       |  Name |              Description                             |
+       +=======+======================================================+
+       | xmlid | The 'xml_id' of the desired :term:`Delivery Service` |
+       +-------+------------------------------------------------------+
+
+Response Structure
+------------------
+.. code-block:: json
+       :caption: Response Example
+
+       {
+               "alerts": [{
+                       "level": "success",
+                       "text": "Successfully deleted URL Sig keys from Traffic 
Vault"
+               }]
+       }
diff --git a/traffic_ops/testing/api/v4/deliveryservices_test.go 
b/traffic_ops/testing/api/v4/deliveryservices_test.go
index 80ced6f..439e7fc 100644
--- a/traffic_ops/testing/api/v4/deliveryservices_test.go
+++ b/traffic_ops/testing/api/v4/deliveryservices_test.go
@@ -44,7 +44,9 @@ func TestDeliveryServices(t *testing.T) {
 
                if includeSystemTests {
                        SSLDeliveryServiceCDNUpdateTest(t)
+                       CreateTestDeliveryServicesURLSigKeys(t)
                        GetTestDeliveryServicesURLSigKeys(t)
+                       DeleteTestDeliveryServicesURLSigKeys(t)
                }
 
                GetTestDeliveryServicesIMS(t)
@@ -1374,6 +1376,63 @@ func GetTestDeliveryServicesURLSigKeys(t *testing.T) {
        }
 }
 
+func CreateTestDeliveryServicesURLSigKeys(t *testing.T) {
+       if len(testData.DeliveryServices) == 0 {
+               t.Fatal("couldn't get the xml ID of test DS")
+       }
+       firstDS := testData.DeliveryServices[0]
+       if firstDS.XMLID == nil {
+               t.Fatal("couldn't get the xml ID of test DS")
+       }
+
+       _, _, err := TOSession.CreateDeliveryServiceURLSigKeys(*firstDS.XMLID, 
nil)
+       if err != nil {
+               t.Error("failed to create url sig keys: " + err.Error())
+       }
+
+       firstKeys, _, err := 
TOSession.GetDeliveryServiceURLSigKeys(*firstDS.XMLID, nil)
+       if err != nil {
+               t.Error("failed to get url sig keys: " + err.Error())
+       }
+       if len(firstKeys) == 0 {
+               t.Errorf("failed to create url sig keys")
+       }
+
+       // Create new keys again and check that they are different
+       _, _, err = TOSession.CreateDeliveryServiceURLSigKeys(*firstDS.XMLID, 
nil)
+       if err != nil {
+               t.Error("failed to create url sig keys: " + err.Error())
+       }
+
+       secondKeys, _, err := 
TOSession.GetDeliveryServiceURLSigKeys(*firstDS.XMLID, nil)
+       if err != nil {
+               t.Error("failed to get url sig keys: " + err.Error())
+       }
+       if len(secondKeys) == 0 {
+               t.Errorf("failed to create url sig keys")
+       }
+
+       if secondKeys["key0"] == firstKeys["key0"] {
+               t.Errorf("second create did not generate new url sig keys")
+       }
+}
+
+func DeleteTestDeliveryServicesURLSigKeys(t *testing.T) {
+       if len(testData.DeliveryServices) == 0 {
+               t.Fatal("couldn't get the xml ID of test DS")
+       }
+       firstDS := testData.DeliveryServices[0]
+       if firstDS.XMLID == nil {
+               t.Fatal("couldn't get the xml ID of test DS")
+       }
+
+       _, _, err := TOSession.DeleteDeliveryServiceURLSigKeys(*firstDS.XMLID, 
nil)
+       if err != nil {
+               t.Error("failed to delete url sig keys: " + err.Error())
+       }
+
+}
+
 func GetDeliveryServiceByLogsEnabled(t *testing.T) {
        if len(testData.DeliveryServices) > 0 {
                firstDS := testData.DeliveryServices[0]
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/urlkey.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/urlkey.go
index 974d05a..bea441b 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/urlkey.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/urlkey.go
@@ -33,6 +33,7 @@ import (
        "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
 )
 
+// GetURLKeysByID returns the URL sig keys for a delivery service identified 
by the id in the path parameter.
 func GetURLKeysByID(w http.ResponseWriter, r *http.Request) {
        inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id"}, 
[]string{"id"})
        if userErr != nil || sysErr != nil {
@@ -85,6 +86,7 @@ func GetURLKeysByID(w http.ResponseWriter, r *http.Request) {
        api.WriteResp(w, r, keys)
 }
 
+// GetURLKeysByName returns the URL sig keys for a delivery service identified 
by the xmlId in the path parameter.
 func GetURLKeysByName(w http.ResponseWriter, r *http.Request) {
        inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"name"}, nil)
        if userErr != nil || sysErr != nil {
@@ -129,6 +131,8 @@ func GetURLKeysByName(w http.ResponseWriter, r 
*http.Request) {
        api.WriteResp(w, r, keys)
 }
 
+// CopyURLKeys copies the URL sig keys from a delivery service in the 
'copy-name' path parameter
+// to the delivery service in the 'name' path parameter.
 func CopyURLKeys(w http.ResponseWriter, r *http.Request) {
        inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"name", 
"copy-name"}, nil)
        if userErr != nil || sysErr != nil {
@@ -208,6 +212,7 @@ func CopyURLKeys(w http.ResponseWriter, r *http.Request) {
        api.WriteRespAlert(w, r, tc.SuccessLevel, "Successfully copied and 
stored keys")
 }
 
+// GenerateURLKeys generates new URL sig keys for the delivery service 
identified by the xmlId in the path parameter.
 func GenerateURLKeys(w http.ResponseWriter, r *http.Request) {
        inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"name"}, nil)
        if userErr != nil || sysErr != nil {
@@ -263,6 +268,7 @@ func GenerateURLKeys(w http.ResponseWriter, r 
*http.Request) {
        api.WriteRespAlert(w, r, tc.SuccessLevel, "Successfully generated and 
stored keys")
 }
 
+// GenerateURLSigKeys generates new URL sig keys.
 func GenerateURLSigKeys() (tc.URLSigKeys, error) {
        chars := 
`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_`
        numKeys := 16
@@ -289,3 +295,106 @@ func GenerateURLSigKeys() (tc.URLSigKeys, error) {
        }
        return keys, nil
 }
+
+// DeleteURLKeysByID deletes the URL sig keys for the delivery service 
identified by the id in the path parameter.
+func DeleteURLKeysByID(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id"}, 
[]string{"id"})
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       if !inf.Config.TrafficVaultEnabled {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
userErr, errors.New("deliveryservice.DeleteURLKeysByID: Traffic Vault is not 
configured"))
+               return
+       }
+
+       dsId := inf.IntParams["id"]
+       ds, ok, err := dbhelpers.GetDSNameFromID(inf.Tx.Tx, dsId)
+       if err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("getting delivery service name from ID: "+err.Error()))
+               return
+       }
+       if !ok {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, 
errors.New("delivery service "+inf.Params["id"]+" not found"), nil)
+               return
+       }
+
+       dsTenantID, ok, err := getDSTenantIDByID(inf.Tx.Tx, inf.IntParams["id"])
+       if err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("checking tenant: "+err.Error()))
+               return
+       }
+       if !ok {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, 
errors.New("delivery service "+inf.Params["id"]+" not found"), nil)
+               return
+       }
+       if authorized, err := tenant.IsResourceAuthorizedToUserTx(*dsTenantID, 
inf.User, inf.Tx.Tx); err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("checking tenant: "+err.Error()))
+               return
+       } else if !authorized {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusForbidden, 
errors.New("not authorized on this tenant"), nil)
+               return
+       }
+
+       err = inf.Vault.DeleteURLSigKeys(string(ds), inf.Tx.Tx, r.Context())
+       if err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("deleting URL Sig keys from Traffic Vault: "+err.Error()))
+               return
+       }
+       api.CreateChangeLogRawTx(api.ApiChange, "DS: "+string(ds)+", ID: 
"+strconv.Itoa(dsId)+", ACTION: Deleted URL sig keys", inf.User, inf.Tx.Tx)
+       api.WriteRespAlert(w, r, tc.SuccessLevel, "Successfully deleted URL Sig 
keys from Traffic Vault")
+}
+
+// DeleteURLKeysByName deletes the URL sig keys for the delivery service 
identified by the xmlId in the path parameter.
+func DeleteURLKeysByName(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"name"}, nil)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       if !inf.Config.TrafficVaultEnabled {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
userErr, errors.New("deliveryservice.DeleteURLKeysByName: Traffic Vault is not 
configured"))
+               return
+       }
+
+       ds := tc.DeliveryServiceName(inf.Params["name"])
+
+       dsTenantID, ok, err := getDSTenantIDByName(inf.Tx.Tx, ds)
+       if err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("checking tenant: "+err.Error()))
+               return
+       }
+       if !ok {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, 
errors.New("delivery service "+string(ds)+" not found"), nil)
+               return
+       }
+       if authorized, err := tenant.IsResourceAuthorizedToUserTx(*dsTenantID, 
inf.User, inf.Tx.Tx); err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("checking tenant: "+err.Error()))
+               return
+       } else if !authorized {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusForbidden, 
errors.New("not authorized on this tenant"), nil)
+               return
+       }
+
+       dsId, ok, err := getDSIDFromName(inf.Tx.Tx, string(ds))
+       if err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("deliveryservice.DeleteURLKeysByName: getting DS ID from name 
"+err.Error()))
+               return
+       } else if !ok {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, 
errors.New("no DS with name "+string(ds)), nil)
+               return
+       }
+
+       err = inf.Vault.DeleteURLSigKeys(string(ds), inf.Tx.Tx, r.Context())
+       if err != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("deleting URL Sig keys from Traffic Vault: "+err.Error()))
+               return
+       }
+
+       api.CreateChangeLogRawTx(api.ApiChange, "DS: "+string(ds)+", ID: 
"+strconv.Itoa(dsId)+", ACTION: Deleted URL sig keys", inf.User, inf.Tx.Tx)
+       api.WriteRespAlert(w, r, tc.SuccessLevel, "Successfully deleted URL Sig 
keys from Traffic Vault")
+}
diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go 
b/traffic_ops/traffic_ops_golang/routing/routes.go
index aaf2bb5..7c44a66 100644
--- a/traffic_ops/traffic_ops_golang/routing/routes.go
+++ b/traffic_ops/traffic_ops_golang/routing/routes.go
@@ -500,7 +500,9 @@ func Routes(d ServerData) ([]Route, []RawRoute, 
http.Handler, error) {
                {api.Version{Major: 4, Minor: 0}, http.MethodPost, 
`deliveryservices/xmlId/{name}/urlkeys/copyFromXmlId/{copy-name}/?$`, 
deliveryservice.CopyURLKeys, auth.PrivLevelOperations, Authenticated, nil, 
42625010763},
                {api.Version{Major: 4, Minor: 0}, http.MethodPost, 
`deliveryservices/xmlId/{name}/urlkeys/generate/?$`, 
deliveryservice.GenerateURLKeys, auth.PrivLevelOperations, Authenticated, nil, 
45304828243},
                {api.Version{Major: 4, Minor: 0}, http.MethodGet, 
`deliveryservices/xmlId/{name}/urlkeys/?$`, deliveryservice.GetURLKeysByName, 
auth.PrivLevelReadOnly, Authenticated, nil, 42027192113},
+               {api.Version{Major: 4, Minor: 0}, http.MethodDelete, 
`deliveryservices/xmlId/{name}/urlkeys/?$`, 
deliveryservice.DeleteURLKeysByName, auth.PrivLevelOperations, Authenticated, 
nil, 42027192114},
                {api.Version{Major: 4, Minor: 0}, http.MethodGet, 
`deliveryservices/{id}/urlkeys/?$`, deliveryservice.GetURLKeysByID, 
auth.PrivLevelReadOnly, Authenticated, nil, 4931971143},
+               {api.Version{Major: 4, Minor: 0}, http.MethodDelete, 
`deliveryservices/{id}/urlkeys/?$`, deliveryservice.DeleteURLKeysByID, 
auth.PrivLevelOperations, Authenticated, nil, 4931971144},
 
                //Delivery service LetsEncrypt
                {api.Version{Major: 4, Minor: 0}, http.MethodPost, 
`deliveryservices/sslkeys/generate/letsencrypt/?$`, 
deliveryservice.GenerateLetsEncryptCertificates, auth.PrivLevelOperations, 
Authenticated, nil, 4534390523},
diff --git 
a/traffic_ops/traffic_ops_golang/trafficvault/backends/disabled/disabled.go 
b/traffic_ops/traffic_ops_golang/trafficvault/backends/disabled/disabled.go
index 81dda37..d18d68b 100644
--- a/traffic_ops/traffic_ops_golang/trafficvault/backends/disabled/disabled.go
+++ b/traffic_ops/traffic_ops_golang/trafficvault/backends/disabled/disabled.go
@@ -81,6 +81,10 @@ func (d *Disabled) PutURLSigKeys(xmlID string, keys 
tc.URLSigKeys, tx *sql.Tx, c
        return disabledErr
 }
 
+func (d *Disabled) DeleteURLSigKeys(xmlID string, tx *sql.Tx, ctx 
context.Context) error {
+       return disabledErr
+}
+
 func (d *Disabled) GetURISigningKeys(xmlID string, tx *sql.Tx, ctx 
context.Context) ([]byte, bool, error) {
        return nil, false, disabledErr
 }
diff --git 
a/traffic_ops/traffic_ops_golang/trafficvault/backends/postgres/postgres.go 
b/traffic_ops/traffic_ops_golang/trafficvault/backends/postgres/postgres.go
index 6dea910..9b1a554 100644
--- a/traffic_ops/traffic_ops_golang/trafficvault/backends/postgres/postgres.go
+++ b/traffic_ops/traffic_ops_golang/trafficvault/backends/postgres/postgres.go
@@ -133,11 +133,32 @@ func (p *Postgres) DeleteDNSSECKeys(cdnName string, tx 
*sql.Tx, ctx context.Cont
 }
 
 func (p *Postgres) GetURLSigKeys(xmlID string, tx *sql.Tx, ctx 
context.Context) (tc.URLSigKeys, bool, error) {
-       return tc.URLSigKeys{}, false, notImplementedErr
+       tvTx, dbCtx, cancelFunc, err := p.beginTransaction(ctx)
+       if err != nil {
+               return tc.URLSigKeys{}, false, err
+       }
+       defer p.commitTransaction(tvTx, dbCtx, cancelFunc)
+       return getURLSigKeys(xmlID, tvTx, ctx)
 }
 
 func (p *Postgres) PutURLSigKeys(xmlID string, keys tc.URLSigKeys, tx *sql.Tx, 
ctx context.Context) error {
-       return notImplementedErr
+       tvTx, dbCtx, cancelFunc, err := p.beginTransaction(ctx)
+       if err != nil {
+               return err
+       }
+       defer p.commitTransaction(tvTx, dbCtx, cancelFunc)
+
+       return putURLSigKeys(xmlID, tvTx, keys, ctx)
+}
+
+func (p *Postgres) DeleteURLSigKeys(xmlID string, tx *sql.Tx, ctx 
context.Context) error {
+       tvTx, dbCtx, cancelFunc, err := p.beginTransaction(ctx)
+       if err != nil {
+               return err
+       }
+       defer p.commitTransaction(tvTx, dbCtx, cancelFunc)
+
+       return deleteURLSigKeys(xmlID, tvTx, ctx)
 }
 
 func (p *Postgres) GetURISigningKeys(xmlID string, tx *sql.Tx, ctx 
context.Context) ([]byte, bool, error) {
diff --git 
a/traffic_ops/traffic_ops_golang/trafficvault/backends/postgres/url_sig_keys.go 
b/traffic_ops/traffic_ops_golang/trafficvault/backends/postgres/url_sig_keys.go
new file mode 100644
index 0000000..93d88cc
--- /dev/null
+++ 
b/traffic_ops/traffic_ops_golang/trafficvault/backends/postgres/url_sig_keys.go
@@ -0,0 +1,82 @@
+package postgres
+
+/*
+ * 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.
+ */
+
+import (
+       "context"
+       "database/sql"
+       "encoding/json"
+       "errors"
+
+       "github.com/apache/trafficcontrol/lib/go-tc"
+
+       "github.com/jmoiron/sqlx"
+)
+
+func getURLSigKeys(xmlID string, tvTx *sqlx.Tx, ctx context.Context) 
(tc.URLSigKeys, bool, error) {
+       var jsonUrlKeys string
+       if err := tvTx.QueryRow("SELECT data FROM url_sig_key WHERE 
deliveryservice = $1", xmlID).Scan(&jsonUrlKeys); err != nil {
+               if err == sql.ErrNoRows {
+                       return tc.URLSigKeys{}, false, nil
+               }
+               e := checkErrWithContext("Traffic Vault PostgreSQL: executing 
SELECT URL Sig Keys query", err, ctx.Err())
+               return tc.URLSigKeys{}, false, e
+       }
+
+       urlSignKey := tc.URLSigKeys{}
+       err := json.Unmarshal([]byte(jsonUrlKeys), &urlSignKey)
+       if err != nil {
+               return tc.URLSigKeys{}, false, errors.New("unmarshalling keys: 
" + err.Error())
+       }
+
+       return urlSignKey, true, nil
+}
+
+func putURLSigKeys(xmlID string, tvTx *sqlx.Tx, keys tc.URLSigKeys, ctx 
context.Context) error {
+       keyJSON, err := json.Marshal(&keys)
+       if err != nil {
+               return errors.New("marshalling keys: " + err.Error())
+       }
+
+       // Delete old keys first if they exist
+       if err = deleteURLSigKeys(xmlID, tvTx, ctx); err != nil {
+               return err
+       }
+
+       res, err := tvTx.Exec("INSERT INTO url_sig_key (deliveryservice, data) 
VALUES ($1, $2)", xmlID, keyJSON)
+       if err != nil {
+               e := checkErrWithContext("Traffic Vault PostgreSQL: executing 
INSERT URL Sig Keys query", err, ctx.Err())
+               return e
+       }
+       if rowsAffected, err := res.RowsAffected(); err != nil {
+               return err
+       } else if rowsAffected == 0 {
+               return errors.New("URL Sign Keys: no keys were inserted")
+       }
+       return nil
+}
+
+func deleteURLSigKeys(xmlID string, tvTx *sqlx.Tx, ctx context.Context) error {
+       if _, err := tvTx.Exec("DELETE FROM url_sig_key WHERE deliveryservice = 
$1", xmlID); err != nil {
+               e := checkErrWithContext("Traffic Vault PostgreSQL: executing 
DELETE URL Sig Keys query", err, ctx.Err())
+               return e
+       }
+       return nil
+}
diff --git 
a/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/dsutil.go 
b/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/dsutil.go
index 5c951ac..203f9a7 100644
--- a/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/dsutil.go
+++ b/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/dsutil.go
@@ -330,6 +330,18 @@ func putURLSigKeys(tx *sql.Tx, authOpts *riak.AuthOptions, 
riakPort *uint, ds tc
        return err
 }
 
+func deleteURLSigningKeys(tx *sql.Tx, authOpts *riak.AuthOptions, riakPort 
*uint, ds tc.DeliveryServiceName) error {
+       cluster, err := getPooledCluster(tx, authOpts, riakPort)
+       if err != nil {
+               return errors.New("getting pooled Riak cluster: " + err.Error())
+       }
+       key := getURLSigConfigFileName(ds)
+       if err := deleteObject(key, urlSigKeysBucket, cluster); err != nil {
+               return errors.New("deleting object: " + err.Error())
+       }
+       return nil
+}
+
 const sslKeysIndex = "sslkeys"
 const cdnSSLKeysLimit = 1000 // TODO: emulates Perl; reevaluate?
 
diff --git 
a/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/riak.go 
b/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/riak.go
index 06069b4..e7fb923 100644
--- a/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/riak.go
+++ b/traffic_ops/traffic_ops_golang/trafficvault/backends/riaksvc/riak.go
@@ -81,6 +81,10 @@ func (r *Riak) PutURLSigKeys(xmlID string, keys 
tc.URLSigKeys, tx *sql.Tx, ctx c
        return putURLSigKeys(tx, &r.cfg.AuthOptions, &r.cfg.Port, 
tc.DeliveryServiceName(xmlID), keys)
 }
 
+func (r *Riak) DeleteURLSigKeys(xmlID string, tx *sql.Tx, ctx context.Context) 
error {
+       return deleteURLSigningKeys(tx, &r.cfg.AuthOptions, &r.cfg.Port, 
tc.DeliveryServiceName(xmlID))
+}
+
 func (r *Riak) GetURISigningKeys(xmlID string, tx *sql.Tx, ctx 
context.Context) ([]byte, bool, error) {
        return getURISigningKeys(tx, &r.cfg.AuthOptions, &r.cfg.Port, xmlID)
 }
diff --git a/traffic_ops/traffic_ops_golang/trafficvault/trafficvault.go 
b/traffic_ops/traffic_ops_golang/trafficvault/trafficvault.go
index fb63067..08031d8 100644
--- a/traffic_ops/traffic_ops_golang/trafficvault/trafficvault.go
+++ b/traffic_ops/traffic_ops_golang/trafficvault/trafficvault.go
@@ -69,6 +69,9 @@ type TrafficVault interface {
        // PutURLSigKeys stores the given URL sig keys for the delivery service 
identified by
        // the given xmlID.
        PutURLSigKeys(xmlID string, keys tc.URLSigKeys, tx *sql.Tx, ctx 
context.Context) error
+       // DeleteURLSigKeys deletes the URL sig keys for the delivery service 
identified
+       // by the given xmlID.
+       DeleteURLSigKeys(xmlID string, tx *sql.Tx, ctx context.Context) error
        // GetURISigningKeys retrieves the URI signing keys (as raw JSON bytes) 
for the delivery
        // service identified by the given xmlID.
        GetURISigningKeys(xmlID string, tx *sql.Tx, ctx context.Context) 
([]byte, bool, error)
diff --git a/traffic_ops/v4-client/deliveryservice.go 
b/traffic_ops/v4-client/deliveryservice.go
index ae6daee..e5887a1 100644
--- a/traffic_ops/v4-client/deliveryservice.go
+++ b/traffic_ops/v4-client/deliveryservice.go
@@ -85,6 +85,12 @@ const (
        // (namely the XMLID of the Delivery Service of interest).
        APIDeliveryServicesURLSigKeys = APIDeliveryServices + 
"/xmlId/%s/urlkeys"
 
+       // APIDeliveryServicesURLSigKeysGenerate is the API path on which 
Traffic Ops provides
+       // functionality to generate new URL-signing keys used by a Delivery 
Service identified
+       // by its XMLID. It is intended to be used with fmt.Sprintf to insert 
its required path parameter
+       // (namely the XMLID of the Delivery Service of interest).
+       APIDeliveryServicesURLSigKeysGenerate = APIDeliveryServices + 
"/xmlId/%s/urlkeys/generate"
+
        // APIDeliveryServicesRegexes is the API path on which Traffic Ops 
serves Delivery Service
        // 'regex' (Regular Expression) information.
        APIDeliveryServicesRegexes = "/deliveryservices_regexes"
@@ -329,6 +335,22 @@ func (to *Session) GetDeliveryServiceURLSigKeys(dsName 
string, header http.Heade
        return data.Response, reqInf, nil
 }
 
+// CreateDeliveryServiceURLSigKeys creates new URL-signing keys used by the 
Delivery Service
+// identified by the XMLID 'dsName'
+func (to *Session) CreateDeliveryServiceURLSigKeys(dsName string, header 
http.Header) (tc.Alerts, toclientlib.ReqInf, error) {
+       var alerts tc.Alerts
+       reqInf, err := 
to.post(fmt.Sprintf(APIDeliveryServicesURLSigKeysGenerate, dsName), nil, 
header, &alerts)
+       return alerts, reqInf, err
+}
+
+// DeleteDeliveryServiceURLSigKeys deletes the URL-signing keys used by the 
Delivery Service
+// identified by the XMLID 'dsName'
+func (to *Session) DeleteDeliveryServiceURLSigKeys(dsName string, header 
http.Header) (tc.Alerts, toclientlib.ReqInf, error) {
+       var alerts tc.Alerts
+       reqInf, err := to.del(fmt.Sprintf(APIDeliveryServicesURLSigKeys, 
dsName), header, &alerts)
+       return alerts, reqInf, err
+}
+
 // GetDeliveryServiceURISigningKeys returns the URI-signing keys used by the 
Delivery Service
 // identified by the XMLID 'dsName'. The result is not parsed.
 func (to *Session) GetDeliveryServiceURISigningKeys(dsName string, header 
http.Header) ([]byte, toclientlib.ReqInf, error) {

Reply via email to