Skip to content

Commit

Permalink
Merge pull request #225 from atlanticwave-sdx/224.delete-connection
Browse files Browse the repository at this point in the history
Handle connection deletions in PCE
  • Loading branch information
sajith authored Apr 19, 2024
2 parents 1a1560a + b381795 commit b931068
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 21 deletions.
61 changes: 50 additions & 11 deletions sdx_controller/controllers/connection_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import json
import logging
import uuid

import connexion
from flask import current_app
Expand Down Expand Up @@ -32,7 +31,30 @@ def delete_connection(connection_id):
:rtype: None
"""
return "do some magic!"
logger.info(
f"Handling delete (connecton id: {connection_id}) "
f"with te_manager: {current_app.te_manager}"
)

# # Looking up by UUID do not seem work yet. Will address in
# # https:/atlanticwave-sdx/sdx-controller/issues/252.
#
# value = db_instance.read_from_db(f"{connection_id}")
# print(f"value: {value}")
# if not value:
# return "Not found", 404

try:
# TODO: pce's unreserve_vlan() method silently returns even if the
# connection_id is not found. This should in fact be an error.
#
# https:/atlanticwave-sdx/pce/issues/180
current_app.te_manager.unreserve_vlan(connection_id)
except Exception as e:
logger.info(f"Delete failed (connection id: {connection_id}): {e}")
return "Failed, reason: {e}", 500

return "OK", 200


def getconnection_by_id(connection_id):
Expand Down Expand Up @@ -66,18 +88,35 @@ def place_connection(body):

logger.info("Placing connection. Saving to database.")

if "id" in body:
connection_id = body["id"]
else:
connection_id = uuid.uuid4()
body["id"] = connection_id
connection_id = body["id"]

db_instance.add_key_value_pair_to_db(connection_id, json.dumps(body))
logger.info("Saving to database complete.")

logger.info(f"Handling request with te_manager: {current_app.te_manager}")
logger.info(
f"Handling request {connection_id} with te_manager: {current_app.te_manager}"
)

reason, code = connection_handler.place_connection(current_app.te_manager, body)
logger.info(f"place_connection result: reason='{reason}', code={code}")

return reason, code
logger.info(
f"place_connection result: ID: {connection_id} reason='{reason}', code={code}"
)

response = {
"connection_id": connection_id,
"status": "OK" if code == 200 else "Failure",
"reason": reason,
}

# # TODO: our response is supposed to be shaped just like request
# # ('#/components/schemas/connection'), and in that case the below
# # code would be a quick implementation.
# #
# # https:/atlanticwave-sdx/sdx-controller/issues/251
# response = body

# response["id"] = connection_id
# response["status"] = "success" if code == 200 else "failure"
# response["reason"] = reason # `reason` is not present in schema though.

return response, code
13 changes: 6 additions & 7 deletions sdx_controller/swagger/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,8 @@ paths:
style: simple
explode: false
schema:
maximum: 10
minimum: 1
type: integer
format: int64
type: string
format: uuid
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -205,10 +203,11 @@ paths:
style: simple
explode: false
schema:
minimum: 1
type: integer
format: int64
type: string
format: uuid
responses:
"200":
description: successful operation
"400":
description: Invalid ID supplied
"404":
Expand Down
90 changes: 87 additions & 3 deletions sdx_controller/test/test_connection_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
class TestConnectionController(BaseTestCase):
"""ConnectionController integration test stubs"""

def test_delete_connection(self):
def test_delete_connection_no_setup(self):
"""
Test case for delete_connection.
Test case for delete_connection().
Delete connection order by ID.
"""
Expand All @@ -28,6 +28,50 @@ def test_delete_connection(self):
)
self.assert200(response, f"Response body is : {response.data.decode('utf-8')}")

def test_delete_connection_with_setup(self):
"""
Test case for delete_connection()
Set up a connection request, get the connection ID from the
response, and then do `DELETE /connection/:connection_id`
"""
# set up temanager connection first
for idx, topology_file in enumerate(
[
TestData.TOPOLOGY_FILE_AMLIGHT,
TestData.TOPOLOGY_FILE_SAX,
TestData.TOPOLOGY_FILE_ZAOXI,
]
):
topology = json.loads(topology_file.read_text())
self.te_manager.add_topology(topology)

request_body = TestData.CONNECTION_REQ.read_text()

connection_response = self.client.open(
f"{BASE_PATH}/connection",
method="POST",
data=request_body,
content_type="application/json",
)

print(f"Response body: {connection_response.data.decode('utf-8')}")

self.assertStatus(connection_response, 200)

connection_id = connection_response.get_json().get("connection_id")
print(f"Deleting request_id: {connection_id}")

delete_response = self.client.open(
f"{BASE_PATH}/connection/{connection_id}",
method="DELETE",
)

self.assert200(
delete_response,
f"Response body is : {delete_response.data.decode('utf-8')}",
)

def test_getconnection_by_id(self):
"""
Test case for getconnection_by_id.
Expand Down Expand Up @@ -106,6 +150,44 @@ def test_place_connection_with_zaoxi(self):
"""
self.__test_with_one_topology(TestData.TOPOLOGY_FILE_ZAOXI)

def test_place_connection_no_id(self):
"""
Test place_connection() with a request that has no ID field.
"""
# Remove ID
request = json.loads(TestData.CONNECTION_REQ.read_text())
request.pop("id")
request = json.dumps(request)

print(f"request: {request} {type(request)}")

response = self.client.open(
f"{BASE_PATH}/connection",
method="POST",
data=request,
content_type="application/json",
)

print(f"response: {response}")
print(f"Response body is : {response.data.decode('utf-8')}")

# Expect a 400 response because the required ID field is
# missing from the request.
self.assertStatus(response, 400)

# JSON response should have a body like:
#
# {
# "detail": "'id' is a required property",
# "status": 400,
# "title": "Bad Request",
# "type": "about:blank"
# }

response = response.get_json()
self.assertEqual(response["status"], 400)
self.assertEqual(response["detail"], "'id' is a required property")

def test_place_connection_with_three_topologies(self):
"""
Test case for place_connection.
Expand Down Expand Up @@ -139,7 +221,9 @@ def test_place_connection_with_three_topologies_added_in_sequence(self):
"""
Test case for place_connection.
Place the same connection request while adding topologies.
Keep placing the same connection request while adding
topologies. The first few requests should fail, and the final
one eventually succeed.
"""
for idx, topology_file in enumerate(
[
Expand Down

0 comments on commit b931068

Please sign in to comment.