Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Added get endpoints for Interface tag ranges #166

Merged
merged 5 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Added
=====
- Added endpoint ``POST v3/interfaces/{interface_id}/tag_ranges`` to set ``tag_ranges`` to interfaces.
- Added endpoint ``DELETE v3/interfaces/{interface_id}/tag_ranges`` to delete ``tag_ranges`` from interfaces.
- Added endpoint ``GET v3/interfaces/{interface_id}/tag_ranges`` to get ``available_tags`` and ``tag_ranges`` from an interface.
- Added endpoint ``GET v3/interfaces/tag_ranges`` to get ``available_tags`` and ``tag_ranges`` from all interfaces.
- Added ``Tag_ranges`` documentation to openapi.yml
- Added API request POST and DELETE to modify ``Interface.tag_ranges``
- Added listener for ``kytos/core.interface_tags`` event to save any changes made to ``Interface`` attributes ``tag_ranges`` and ``available_tags``
Expand Down
29 changes: 29 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,35 @@ def delete_tag_range(self, request: Request) -> JSONResponse:
raise HTTPException(400, detail=detail)
return JSONResponse("Operation Successful", status_code=200)

@rest('v3/interfaces/tag_ranges', methods=['GET'])
@validate_openapi(spec)
def get_all_tag_ranges(self, _: Request) -> JSONResponse:
"""Get all tag_ranges and available_tags from interfaces"""
result = {}
for switch in self.controller.switches.copy().values():
for interface in switch.interfaces.copy().values():
result[interface.id] = {
"available_tags": interface.available_tags,
"tag_ranges": interface.tag_ranges
}
return JSONResponse(result, status_code=200)

@rest('v3/interfaces/{interface_id}/tag_ranges', methods=['GET'])
@validate_openapi(spec)
def get_tag_ranges_by_intf(self, request: Request) -> JSONResponse:
"""Get tag_ranges and available_tags an interface"""
interface_id = request.path_params["interface_id"]
interface = self.controller.get_interface_by_id(interface_id)
if not interface:
raise HTTPException(404, detail="Interface not found")
result = {
interface_id: {
"available_tags": interface.available_tags,
"tag_ranges": interface.tag_ranges
}
}
return JSONResponse(result, status_code=200)

# Link related methods
@rest('v3/links')
def get_links(self, _request: Request) -> JSONResponse:
Expand Down
63 changes: 63 additions & 0 deletions openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,59 @@ paths:
schema:
type: string
example: Switch not found
/v3/interfaces/tag_ranges:
get:
summary: Get tag_ranges and available_tags from all interface
responses:
'200':
description: Ok
content:
application/json:
schema:
type: object
viniarck marked this conversation as resolved.
Show resolved Hide resolved
properties:
interface_id:
type: object
properties:
tag_ranges:
$ref: '#/components/schemas/InterfaceRanges'
available_tags:
$ref: '#/components/schemas/InterfaceRanges'
example:
"00:00:00:00:00:00:00:01:2":
"available_tags": [[1, 4096]]
"tag_ranges": [[1,4096]]
/v3/interfaces/{interface_id}/tag_ranges:
get:
summary: Get tag_ranges and available_tags from an interface
parameters:
- name: interface_id
schema:
type: string
required: true
description: The interface ID
in: path
responses:
'200':
description: Ok
content:
application/json:
schema:
type: object
viniarck marked this conversation as resolved.
Show resolved Hide resolved
properties:
interface_id:
type: object
properties:
tag_ranges:
$ref: '#/components/schemas/InterfaceRanges'
available_tags:
$ref: '#/components/schemas/InterfaceRanges'
example:
"00:00:00:00:00:00:00:01:2":
"available_tags": [[1, 4096]]
"tag_ranges": [[1,4096]]
'404':
description: Interface not found
post:
summary: Set tag_range from an interface
parameters:
Expand Down Expand Up @@ -753,3 +805,14 @@ components:
- type: array
- type: integer
example: [[1, 500], 2096, [3001]]
InterfaceRanges: # Can be referenced via '#/components/schemas/InterfaceRanges'
type: object
properties:
vlan:
type: array
items:
type: array
items:
type: integer
minItems: 2
maxItems: 2
54 changes: 54 additions & 0 deletions tests/unit/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1807,3 +1807,57 @@ async def test_delete_tag_range_type_error(self, event_loop):
url = f"{self.base_endpoint}/interfaces/{interface_id}/tag_ranges"
response = await self.api_client.delete(url)
assert response.status_code == 400

async def test_get_all_tag_ranges(self, event_loop):
"""Test get_all_tag_ranges"""
self.napp.controller.loop = event_loop
dpid = '00:00:00:00:00:00:00:01'
switch = get_switch_mock(dpid)
interface = get_interface_mock('s1-eth1', 1, switch)
tags = {'vlan': [[1, 4095]]}
interface.tag_ranges = tags
interface.available_tags = tags
switch.interfaces = {1: interface}
self.napp.controller.switches = {dpid: switch}
url = f"{self.base_endpoint}/interfaces/tag_ranges"
response = await self.api_client.get(url)
expected = {dpid: {
'1': {
viniarck marked this conversation as resolved.
Show resolved Hide resolved
'available_tags': tags,
'tag_ranges': tags
}
}}
assert response.status_code == 200
assert response.json() == expected

async def test_get_tag_ranges_by_intf(self, event_loop):
"""Test get_tag_ranges_by_intf"""
self.napp.controller.loop = event_loop
dpid = '00:00:00:00:00:00:00:01'
switch = get_switch_mock(dpid)
interface = get_interface_mock('s1-eth1', 1, switch)
tags = {'vlan': [[1, 4095]]}
interface.tag_ranges = tags
interface.available_tags = tags
self.napp.controller.get_interface_by_id = MagicMock()
self.napp.controller.get_interface_by_id.return_value = interface
url = f"{self.base_endpoint}/interfaces/{dpid}:1/tag_ranges"
response = await self.api_client.get(url)
expected = {
'00:00:00:00:00:00:00:01:1': {
"available_tags": tags,
"tag_ranges": tags
}
}
assert response.status_code == 200
assert response.json() == expected

async def test_get_tag_ranges_by_intf_error(self, event_loop):
"""Test get_tag_ranges_by_intf with NotFound"""
self.napp.controller.loop = event_loop
dpid = '00:00:00:00:00:00:00:01'
self.napp.controller.get_interface_by_id = MagicMock()
self.napp.controller.get_interface_by_id.return_value = None
url = f"{self.base_endpoint}/interfaces/{dpid}:1/tag_ranges"
response = await self.api_client.get(url)
assert response.status_code == 404