Skip to content

Commit

Permalink
Merge pull request #324 from atlanticwave-sdx/patch-connection
Browse files Browse the repository at this point in the history
Implement PATCH connection
  • Loading branch information
congwang09 authored Aug 30, 2024
2 parents 13f0662 + fc98a86 commit 9afb868
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 57 deletions.
84 changes: 55 additions & 29 deletions sdx_controller/controllers/l2vpn_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,32 @@ def delete_connection(service_id):
:rtype: None
"""
connection_id = service_id

logger.info(
f"Handling delete (service id: {connection_id}) "
f"Handling delete (service id: {service_id}) "
f"with te_manager: {current_app.te_manager}"
)

# # Looking up by UUID do not seem work yet. Will address in
# # https://github.com/atlanticwave-sdx/sdx-controller/issues/252.
#
# value = db_instance.read_from_db(f"{connection_id}")
# value = db_instance.read_from_db(f"{service_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.
# service_id is not found. This should in fact be an error.
#
# https://github.com/atlanticwave-sdx/pce/issues/180
connection = db_instance.read_from_db("connections", f"{connection_id}")
connection = db_instance.read_from_db("connections", f"{service_id}")
if not connection:
return "Did not find connection", 404
connection_handler.remove_connection(current_app.te_manager, connection_id)
db_instance.mark_deleted("connections", f"{connection_id}")
db_instance.mark_deleted("breakdowns", f"{connection_id}")
connection_handler.remove_connection(current_app.te_manager, service_id)
db_instance.mark_deleted("connections", f"{service_id}")
db_instance.mark_deleted("breakdowns", f"{service_id}")
except Exception as e:
logger.info(f"Delete failed (connection id: {connection_id}): {e}")
logger.info(f"Delete failed (connection id: {service_id}): {e}")
return f"Failed, reason: {e}", 500

return "OK", 200
Expand All @@ -79,11 +77,10 @@ def getconnection_by_id(service_id):
:rtype: Connection
"""

connection_id = service_id
value = db_instance.read_from_db("connections", f"{connection_id}")
value = db_instance.read_from_db("connections", f"{service_id}")
if not value:
return "Connection not found", 404
return json.loads(value[connection_id])
return json.loads(value[service_id])


def getconnections(): # noqa: E501
Expand All @@ -98,8 +95,8 @@ def getconnections(): # noqa: E501
return "No connection was found", 404
return_values = {}
for connection in values:
connection_id = next(iter(connection))
return_values[connection_id] = json.loads(connection[connection_id])
service_id = next(iter(connection))
return_values[service_id] = json.loads(connection[service_id])
return return_values


Expand All @@ -121,32 +118,32 @@ def place_connection(body):

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

connection_id = body.get("id")
service_id = body.get("id")

if connection_id is None:
connection_id = str(uuid.uuid4())
body["id"] = connection_id
logger.info(f"Request has no ID. Generated ID: {connection_id}")
if service_id is None:
service_id = str(uuid.uuid4())
body["id"] = service_id
logger.info(f"Request has no ID. Generated ID: {service_id}")

logger.info("Saving to database complete.")

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

reason, code = connection_handler.place_connection(current_app.te_manager, body)

if code == 200:
db_instance.add_key_value_pair_to_db(
"connections", connection_id, json.dumps(body)
"connections", service_id, json.dumps(body)
)

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

response = {
"service_id": connection_id,
"service_id": service_id,
"status": "OK" if code == 200 else "Failure",
"reason": reason,
}
Expand All @@ -158,14 +155,14 @@ def place_connection(body):
# # https://github.com/atlanticwave-sdx/sdx-controller/issues/251
# response = body

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

return response, code


def patch_connection(connection_id, body=None): # noqa: E501
def patch_connection(service_id, body=None): # noqa: E501
"""Edit and change an existing L2vpn connection by ID from the SDX-Controller
# noqa: E501
Expand All @@ -177,16 +174,45 @@ def patch_connection(connection_id, body=None): # noqa: E501
:rtype: Connection
"""
value = db_instance.read_from_db("connections", f"{connection_id}")
value = db_instance.read_from_db("connections", f"{service_id}")
if not value:
return "Connection not found", 404

logger.info(f"Changed connection: {body}")
if not connexion.request.is_json:
return "Request body must be JSON", 400

body = L2vpnServiceIdBody.from_dict(connexion.request.get_json()) # noqa: E501

logger.info(f"Gathered connexion JSON: {body}")

return json.loads(value[connection_id])
new_service_id = str(uuid.uuid4())
body["id"] = new_service_id
logger.info(f"Request has no ID. Generated ID: {service_id}")

try:
logger.info("Removing connection")
connection_handler.remove_connection(current_app.te_manager, service_id)
db_instance.mark_deleted("connections", f"{service_id}")
db_instance.mark_deleted("breakdowns", f"{service_id}")
logger.info("Removed connection: ", service_id)
logger.info(
f"Placing new connection {service_id} with te_manager: {current_app.te_manager}"
)
reason, code = connection_handler.place_connection(current_app.te_manager, body)
if code == 200:
db_instance.add_key_value_pair_to_db(
"connections", service_id, json.dumps(body)
)
logger.info(
f"place_connection result: ID: {service_id} reason='{reason}', code={code}"
)
response = {
"service_id": service_id,
"status": "OK" if code == 200 else "Failure",
"reason": reason,
}
except Exception as e:
logger.info(f"Delete failed (connection id: {service_id}): {e}")
return f"Failed, reason: {e}", 500

return response, code
20 changes: 12 additions & 8 deletions sdx_controller/handlers/connection_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,18 @@ def place_connection(
logger.error(f"Error when generating/publishing breakdown: {e} - {err}")
return f"Error: {e}", 400

def remove_connection(self, te_manager, connection_id) -> Tuple[str, int]:
te_manager.unreserve_vlan(connection_id)
breakdown = self.db_instance.read_from_db("breakdowns", connection_id)[
connection_id
]
connection_request = self.db_instance.read_from_db(
"connections", connection_id
)[connection_id]
def remove_connection(self, te_manager, service_id) -> Tuple[str, int]:
te_manager.unreserve_vlan(service_id)
connection_request = self.db_instance.read_from_db("connections", service_id)
if not connection_request:
return "Did not find connection request, cannot remove connection", 404

connection_request = connection_request[service_id]

breakdown = self.db_instance.read_from_db("breakdowns", service_id)
if not breakdown:
return "Did not find breakdown, cannot remove connection", 404
breakdown = breakdown[service_id]

try:
status, code = self._send_breakdown_to_lc(
Expand Down
40 changes: 20 additions & 20 deletions sdx_controller/test/test_l2vpn_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ def test_delete_connection_no_setup(self):
Delete connection order by ID.
"""
connection_id = 2
service_id = 2
response = self.client.open(
f"{BASE_PATH}/l2vpn/1.0/{connection_id}",
f"{BASE_PATH}/l2vpn/1.0/{service_id}",
method="DELETE",
)
self.assert404(response, f"Response body is : {response.data.decode('utf-8')}")
Expand All @@ -53,7 +53,7 @@ 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 /l2vpn/1.0/:connection_id`
response, and then do `DELETE /l2vpn/1.0/:service_id`
"""
# set up temanager connection first
self.__add_the_three_topologies()
Expand All @@ -71,11 +71,11 @@ def test_delete_connection_with_setup(self):

self.assertStatus(connection_response, 200)

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

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

Expand All @@ -90,14 +90,14 @@ def test_getconnection_by_id(self):
Find connection by ID.
"""
connection_id = 10
service_id = 10
response = self.client.open(
f"{BASE_PATH}/l2vpn/1.0/{connection_id}",
f"{BASE_PATH}/l2vpn/1.0/{service_id}",
method="GET",
)

# The connection_id we've supplied above should not exist.
# TODO: test for existing connection_id. See
# The service_id we've supplied above should not exist.
# TODO: test for existing service_id. See
# https://github.com/atlanticwave-sdx/sdx-controller/issues/34.
self.assertStatus(response, 404)

Expand Down Expand Up @@ -324,8 +324,8 @@ def test_place_connection_v2_with_three_topologies_400_response(self):

# Returned connection ID should be different from the original
# request ID.
connection_id = response.get_json().get("service_id")
self.assertNotEqual(connection_id, original_request_id)
service_id = response.get_json().get("service_id")
self.assertNotEqual(service_id, original_request_id)

def test_place_connection_v2_with_three_topologies_200_response(self):
"""
Expand Down Expand Up @@ -368,17 +368,17 @@ def test_place_connection_v2_with_three_topologies_200_response(self):

# Returned connection ID should be different from the original
# request ID.
connection_id = response.get_json().get("service_id")
self.assertNotEqual(connection_id, original_request_id)
service_id = response.get_json().get("service_id")
self.assertNotEqual(service_id, original_request_id)

def test_z100_getconnection_by_id_expect_404(self):
"""
Test getconnection_by_id with a non-existent connection ID.
"""
# Generate a random ID.
connection_id = uuid.uuid4()
service_id = uuid.uuid4()
response = self.client.open(
f"{BASE_PATH}/l2vpn/1.0/{connection_id}",
f"{BASE_PATH}/l2vpn/1.0/{service_id}",
method="GET",
)

Expand Down Expand Up @@ -406,12 +406,12 @@ def test_z100_getconnection_by_id_expect_200(self):

self.assertStatus(post_response, 200)

connection_id = post_response.get_json().get("service_id")
print(f"Got connection_id: {connection_id}")
service_id = post_response.get_json().get("service_id")
print(f"Got service_id: {service_id}")

# Now try `GET /l2vpn/1.0/{connection_id}`
# Now try `GET /l2vpn/1.0/{service_id}`
get_response = self.client.open(
f"{BASE_PATH}/l2vpn/1.0/{connection_id}",
f"{BASE_PATH}/l2vpn/1.0/{service_id}",
method="GET",
)

Expand Down

0 comments on commit 9afb868

Please sign in to comment.