Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Added an optimistic quorum feature to Traffic Monitor to prevent false negative states from propagating to downstream components in the event of network isolation.
- Traffic Ops Golang Endpoints
- /api/1.1/cachegroupparameters/{{cachegroupID}}/{{parameterID}} `(DELETE)`
- /api/1.5/to_extensions/:id `(DELETE)`
- /api/1.5/to_extensions `(POST)`

### Changed
Expand All @@ -20,6 +21,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- /cachegroups/:parameterID/parameter/available
- /cachegroup/:parameterID/parameter
- /api_capabilities/:id
- /to_extensions/:id/delete
- /regions/:region_name/phys_locations
- /parameters/validate
- /divisions/:division_name/regions
Expand Down
76 changes: 76 additions & 0 deletions docs/source/api/to_extensions_id.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
..
..
.. 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-to_extensions-id:

************************
``to_extensions/{{ID}}``
************************
.. versionadded:: 1.5

Comment thread
ocket8888 marked this conversation as resolved.
``DELETE``
==========
Deletes a Traffic Ops extension definition. This does **not** delete the actual extension file.

:Auth. Required: Yes
:Roles Required: None\ [1]_
:Response Type: ``undefined``

Request Structure
-----------------
.. table:: Request Path Parameters

+------+---------------------------------------------------------------------------+
| Name | Description |
+======+===========================================================================+
| ID | The integral, unique identifier of the extension definition to be deleted |
+------+---------------------------------------------------------------------------+

.. code-block:: http
:caption: Request Example

DELETE /api/1.5/to_extensions/16 HTTP/1.1
Host: trafficops.infra.ciab.test
User-Agent: curl/7.47.0
Accept: */*
Cookie: mojolicious=...

Response Structure
------------------
.. code-block:: http
:caption: Response Example

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json
Date: Wed, 12 Dec 2018 16:33:52 GMT
Server: Mojolicious (Perl)
Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly
Vary: Accept-Encoding
Whole-Content-Sha512: EB0Nu85azbGzaehDTAODP3NPqWbByIza1XQhgwtsW2WTXyK/dxQtncp0YiJXyO0tH9H+n+6BBfojBOb5h0dFPA==
Content-Length: 60

{ "alerts": [
{
"level": "success",
"text": "Extension deleted."
}
]}

.. [1] No roles are required to use this endpoint, however access is controlled by username. Only the reserved user ``extension`` is permitted the use of this endpoint.
6 changes: 6 additions & 0 deletions docs/source/api/to_extensions_id_delete.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*******************************
``to_extensions/{{ID}}/delete``
*******************************
.. deprecated:: ATCv4
Comment thread
mhoppa marked this conversation as resolved.
Use the ``DELETE`` method of :ref:`to-api-to_extensions-id` instead.

``POST``
========
Expand Down Expand Up @@ -69,6 +71,10 @@ Response Structure
{
"level": "success",
"text": "Extension deleted."
},
{
"level": "warning",
"text": "This endpoint is deprecated, please use 'DELETE /to_extensions/:id' instead"
}
]}

Expand Down
9 changes: 5 additions & 4 deletions traffic_ops/app/lib/API/ToExtension.pm
Original file line number Diff line number Diff line change
Expand Up @@ -196,19 +196,20 @@ sub delete {

my $new_id = 1;
my $id = $self->param('id');
my $alt = "DELETE /to_extensions/:id";

# print Dumper($self->req);
if ( $self->current_user()->{username} ne "extension" ) {
return $self->alert( { error => "Invalid user for this API. Only the \"extension\" user can use this." } );
return $self->with_deprecation("Invalid user for this API. Only the \"extension\" user can use this.", "error", 400, $alt);
}

if ( !defined($id) ) {
return $self->alert( { error => "ToExtension delete requires an id." } );
return $self->with_deprecation("ToExtension delete requires an id.", "error", 400, $alt);
}
else {
my $delete = $self->db->resultset('ToExtension')->search( { id => $id } )->single();
if ( !defined($delete) ) {
return $self->alert( { error => "ToExtension with id " . $id . " not found." } );
return $self->with_deprecation("ToExtension with id " . $id . " not found.", "error", 400, $alt);
}
if ( $delete->type->name =~ /^CHECK_EXTENSION_/ ) {
my $open_type_id = &type_id( $self, 'CHECK_EXTENSION_OPEN_SLOT' );
Expand All @@ -229,7 +230,7 @@ sub delete {
$delete->delete();
}
}
return $self->success_message("Extension deleted.");
return $self->with_deprecation("Extension deleted.", "success", 200, $alt);
}

1;
4 changes: 2 additions & 2 deletions traffic_ops/client/toextension.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ func (to *Session) CreateTOExtension(toExtension tc.TOExtensionNullable) (tc.Ale

// DeleteToExtension deletes a to_extension
func (to *Session) DeleteTOExtension(id int) (tc.Alerts, ReqInf, error) {
URI := fmt.Sprintf("%s/%d/delete", API_TO_EXTENSION, id)
resp, remoteAddr, err := to.request(http.MethodPost, URI, nil)
URI := fmt.Sprintf("%s/%d", API_TO_EXTENSION, id)
resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil)
reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
if err != nil {
return tc.Alerts{}, reqInf, err
Expand Down
1 change: 1 addition & 0 deletions traffic_ops/traffic_ops_golang/routing/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) {

// TO Extensions
{1.5, http.MethodPost, `to_extensions$`, toextension.CreateTOExtension, auth.PrivLevelReadOnly, Authenticated, nil, 380498599, noPerlBypass},
{1.5, http.MethodDelete, `to_extensions/{id}$`, toextension.Delete, auth.PrivLevelReadOnly, Authenticated, nil, 380498299, noPerlBypass},

//Pattern based consistent hashing endpoint
{1.4, http.MethodPost, `consistenthash/?$`, consistenthash.Post, auth.PrivLevelReadOnly, Authenticated, nil, 1960755076, noPerlBypass},
Expand Down
66 changes: 65 additions & 1 deletion traffic_ops/traffic_ops_golang/toextension/toextension.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"net/http"

"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/dbhelpers"
"github.com/jmoiron/sqlx"
Expand Down Expand Up @@ -123,7 +124,6 @@ func createCheckExt(toExt tc.TOExtensionNullable, tx *sqlx.Tx) (int, error, erro
return 0, nil, fmt.Errorf("reset servercheck table for new check extension: %v", err)
}
return id, nil, nil

}

func checkDupTOCheckExtension(colName, value string, tx *sqlx.Tx) (error, error) {
Expand Down Expand Up @@ -154,3 +154,67 @@ func updateQuery() string {
WHERE id=:id
`
}

// Delete is the handler for deleting to_extensions.
func Delete(w http.ResponseWriter, r *http.Request) {
inf, sysErr, userErr, errCode := api.NewInfo(r, []string{"id"}, []string{"id"})
tx := inf.Tx.Tx
if sysErr != nil || userErr != nil {
api.HandleErr(w, r, tx, errCode, userErr, sysErr)
return
}
defer inf.Close()

if inf.User.UserName != "extension" {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusForbidden, errors.New("invalid user for this API. Only the \"extension\" user can use this"), nil)
return
}

id := inf.IntParams["id"]
userErr, sysErr, errCode = deleteTOExtension(id, inf.Tx)
if userErr != nil || sysErr != nil {
api.HandleErr(w, r, tx, errCode, userErr, sysErr)
return
}

changeLogMsg := fmt.Sprintf("TO_EXTENSION: %d, ID: %d, ACTION: Deleted", id, id)
api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, inf.Tx.Tx)
api.WriteRespAlert(w, r, tc.SuccessLevel, "Extension deleted.")
}

func deleteTOExtension(id int, tx *sqlx.Tx) (error, error, int) {
// Get Open Slot Type ID
openID, exists, err := dbhelpers.GetTypeIDByName("CHECK_EXTENSION_OPEN_SLOT", tx.Tx)
if !exists {
return nil, errors.New("expected type CHECK_EXTENSION_OPEN_SLOT does not exist in type table"), http.StatusInternalServerError
} else if err != nil {
return nil, fmt.Errorf("getting CHECK_EXTENSION_OPEN_SLOT type id: %v", err), http.StatusInternalServerError
}

openTOExt := tc.TOExtensionNullable{
Name: util.StrPtr("OPEN"),
Version: util.StrPtr("0"),
InfoURL: util.StrPtr(""),
ScriptFile: util.StrPtr(""),
IsActive: util.IntPtr(0),
AdditionConfigJSON: util.StrPtr(""),
ServercheckShortName: util.StrPtr(""),
TypeID: &openID,
ID: &id,
}

result, err := tx.NamedExec(updateQuery(), openTOExt)
if err != nil {
return api.ParseDBError(err)
}

if rowsAffected, err := result.RowsAffected(); err != nil {
return nil, fmt.Errorf("deleting TO Extension: getting rows affected: %v", err), http.StatusInternalServerError
} else if rowsAffected < 1 {
return fmt.Errorf("no TO Extension with that key found"), nil, http.StatusNotFound
} else if rowsAffected > 1 {
return nil, fmt.Errorf("TO Extension delete affected too many rows: %d", rowsAffected), http.StatusInternalServerError
}

return nil, nil, http.StatusOK
}