Skip to content
Snippets Groups Projects
Commit 7b4d8ca9 authored by geant-release-service's avatar geant-release-service
Browse files

Finished release 0.4.

parents 5223a4e8 a7823bb4
No related branches found
No related tags found
No related merge requests found
Pipeline #85542 passed
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [0.3] - 2024-01-26
- Added Token authentication for LSO callbacks.
## [0.3] - 2024-01-23 ## [0.3] - 2024-01-23
- Fixed related to the Authentication and some small improvments. - Fixed related to the Authentication and some small improvments.
......
...@@ -8,13 +8,13 @@ from orchestrator.domain import SubscriptionModel ...@@ -8,13 +8,13 @@ from orchestrator.domain import SubscriptionModel
from orchestrator.schemas import SubscriptionDomainModelSchema from orchestrator.schemas import SubscriptionDomainModelSchema
from orchestrator.services.subscriptions import build_extended_domain_model from orchestrator.services.subscriptions import build_extended_domain_model
from gso.auth.security import opa_security_default from gso.auth.api_key_auth import get_api_key
from gso.services.subscriptions import get_active_router_subscriptions from gso.services.subscriptions import get_active_router_subscriptions
router = APIRouter( router = APIRouter(
prefix="/subscriptions", prefix="/subscriptions",
tags=["Subscriptions"], tags=["Subscriptions"],
dependencies=[Depends(opa_security_default)], dependencies=[Depends(get_api_key)],
) )
......
"""Manage API key validation for FastAPI routes."""
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from gso.settings import load_oss_params
security = HTTPBearer()
async def get_api_key(
credentials: HTTPAuthorizationCredentials = Depends(security), # noqa: B008
) -> str:
"""Validate the provided API key against known third-party keys and returns it if valid, else raises HTTP 403."""
settings = load_oss_params()
api_key = credentials.credentials
# TODO: This is a simulated database of API keys which should be replace with a real one
if api_key in settings.THIRD_PARTY_API_KEYS.values():
return api_key
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Invalid API Key")
...@@ -73,5 +73,9 @@ ...@@ -73,5 +73,9 @@
"broker_url": "redis://localhost:6379/0", "broker_url": "redis://localhost:6379/0",
"result_backend": "rpc://localhost:6379/0", "result_backend": "rpc://localhost:6379/0",
"result_expires": 3600 "result_expires": 3600
},
"THIRD_PARTY_API_KEYS": {
"AnsibleDynamicInventoryGenerator": "REALLY_random_AND_secure_T0keN",
"Application_2": "another_REALY_random_AND_3cure_T0keN"
} }
} }
...@@ -62,8 +62,8 @@ def execute_playbook( ...@@ -62,8 +62,8 @@ def execute_playbook(
.. code-block:: json .. code-block:: json
"inventory": { "inventory": {
"_meta": { "all": {
"vars": { "hosts": {
"host1.local": { "host1.local": {
"foo": "bar" "foo": "bar"
}, },
...@@ -71,12 +71,6 @@ def execute_playbook( ...@@ -71,12 +71,6 @@ def execute_playbook(
"key": "value" "key": "value"
} }
} }
},
"all": {
"hosts": {
"host1.local": null,
"host2.local": null
}
} }
} }
......
...@@ -161,6 +161,7 @@ class OSSParams(BaseSettings): ...@@ -161,6 +161,7 @@ class OSSParams(BaseSettings):
MONITORING: MonitoringParams MONITORING: MonitoringParams
PROVISIONING_PROXY: ProvisioningProxyParams PROVISIONING_PROXY: ProvisioningProxyParams
CELERY: CeleryParams CELERY: CeleryParams
THIRD_PARTY_API_KEYS: dict[str, str]
def load_oss_params() -> OSSParams: def load_oss_params() -> OSSParams:
......
...@@ -59,23 +59,22 @@ def calculate_pe_router_list() -> State: ...@@ -59,23 +59,22 @@ def calculate_pe_router_list() -> State:
def _generate_pe_inventory(pe_router_list: list[Router]) -> dict[str, Any]: def _generate_pe_inventory(pe_router_list: list[Router]) -> dict[str, Any]:
"""Generate an Ansible-compatible inventory for executing playbooks. Contains all active PE routers.""" """Generate an Ansible-compatible inventory for executing playbooks. Contains all active PE routers."""
return { return {
"_meta": { "all": {
"vars": { "hosts": {
router.router.router_fqdn: { router.router.router_fqdn: {
"lo4": str(router.router.router_lo_ipv4_address), "lo4": str(router.router.router_lo_ipv4_address),
"lo6": str(router.router.router_lo_ipv6_address), "lo6": str(router.router.router_lo_ipv6_address),
"vendor": router.router.vendor, "vendor": str(router.router.vendor),
} }
for router in pe_router_list for router in pe_router_list
} }
}, },
"all": {"hosts": {router.router.router_fqdn: None for router in pe_router_list}},
} }
@step("[DRY RUN] Add P router to iBGP mesh") @step("[DRY RUN] Add P router to iBGP mesh")
def add_p_to_mesh_dry( def add_p_to_mesh_dry(
subscription: Router, callback_route: str, pe_router_list: list[Router], tt_number: str, process_id: UUIDstr subscription: dict[str, Any], callback_route: str, pe_router_list: list[Router], tt_number: str, process_id: UUIDstr
) -> None: ) -> None:
"""Perform a dry run of adding the new P router to the PE router mesh.""" """Perform a dry run of adding the new P router to the PE router mesh."""
extra_vars = { extra_vars = {
...@@ -95,7 +94,7 @@ def add_p_to_mesh_dry( ...@@ -95,7 +94,7 @@ def add_p_to_mesh_dry(
@step("[FOR REAL] Add P router to iBGP mesh") @step("[FOR REAL] Add P router to iBGP mesh")
def add_p_to_mesh_real( def add_p_to_mesh_real(
subscription: Router, callback_route: str, pe_router_list: list[Router], tt_number: str, process_id: UUIDstr subscription: dict[str, Any], callback_route: str, pe_router_list: list[Router], tt_number: str, process_id: UUIDstr
) -> None: ) -> None:
"""Add the P router to the mesh of PE routers.""" """Add the P router to the mesh of PE routers."""
extra_vars = { extra_vars = {
...@@ -115,7 +114,7 @@ def add_p_to_mesh_real( ...@@ -115,7 +114,7 @@ def add_p_to_mesh_real(
@step("[DRY RUN] Add all PE routers to P router iBGP table") @step("[DRY RUN] Add all PE routers to P router iBGP table")
def add_all_pe_to_p_dry( def add_all_pe_to_p_dry(
subscription: Router, pe_router_list: list[Router], callback_route: str, tt_number: str, process_id: UUIDstr subscription: dict[str, Any], pe_router_list: list[Router], callback_route: str, tt_number: str, process_id: UUIDstr
) -> None: ) -> None:
"""Perform a dry run of adding the list of all PE routers to the new P router.""" """Perform a dry run of adding the list of all PE routers to the new P router."""
extra_vars = { extra_vars = {
...@@ -136,14 +135,14 @@ def add_all_pe_to_p_dry( ...@@ -136,14 +135,14 @@ def add_all_pe_to_p_dry(
provisioning_proxy.execute_playbook( provisioning_proxy.execute_playbook(
playbook_name="update_ibgp_mesh.yaml", playbook_name="update_ibgp_mesh.yaml",
callback_route=callback_route, callback_route=callback_route,
inventory=subscription.router.router_fqdn, inventory=subscription["router"]["router_fqdn"],
extra_vars=extra_vars, extra_vars=extra_vars,
) )
@step("[FOR REAL] Add all PE routers to P router iBGP table") @step("[FOR REAL] Add all PE routers to P router iBGP table")
def add_all_pe_to_p_real( def add_all_pe_to_p_real(
subscription: Router, pe_router_list: list[Router], callback_route: str, tt_number: str, process_id: UUIDstr subscription: dict[str, Any], pe_router_list: list[Router], callback_route: str, tt_number: str, process_id: UUIDstr
) -> None: ) -> None:
"""Add the list of all PE routers to the new P router.""" """Add the list of all PE routers to the new P router."""
extra_vars = { extra_vars = {
...@@ -164,7 +163,7 @@ def add_all_pe_to_p_real( ...@@ -164,7 +163,7 @@ def add_all_pe_to_p_real(
provisioning_proxy.execute_playbook( provisioning_proxy.execute_playbook(
playbook_name="update_ibgp_mesh.yaml", playbook_name="update_ibgp_mesh.yaml",
callback_route=callback_route, callback_route=callback_route,
inventory=subscription.router.router_fqdn, inventory=subscription["router"]["router_fqdn"],
extra_vars=extra_vars, extra_vars=extra_vars,
) )
......
...@@ -2,7 +2,7 @@ from setuptools import find_packages, setup ...@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
setup( setup(
name="geant-service-orchestrator", name="geant-service-orchestrator",
version="0.3", version="0.4",
author="GÉANT", author="GÉANT",
author_email="swd@geant.org", author_email="swd@geant.org",
description="GÉANT Service Orchestrator", description="GÉANT Service Orchestrator",
......
...@@ -3,14 +3,30 @@ from orchestrator.types import SubscriptionLifecycle ...@@ -3,14 +3,30 @@ from orchestrator.types import SubscriptionLifecycle
ROUTER_SUBSCRIPTION_ENDPOINT = "/api/v1/subscriptions/routers" ROUTER_SUBSCRIPTION_ENDPOINT = "/api/v1/subscriptions/routers"
def test_router_subscriptions_endpoint(test_client, nokia_router_subscription_factory): def test_router_subscriptions_endpoint_with_valid_api_key(test_client, nokia_router_subscription_factory):
nokia_router_subscription_factory() nokia_router_subscription_factory()
nokia_router_subscription_factory() nokia_router_subscription_factory()
nokia_router_subscription_factory() nokia_router_subscription_factory()
nokia_router_subscription_factory(status=SubscriptionLifecycle.TERMINATED) nokia_router_subscription_factory(status=SubscriptionLifecycle.TERMINATED)
nokia_router_subscription_factory(status=SubscriptionLifecycle.INITIAL) nokia_router_subscription_factory(status=SubscriptionLifecycle.INITIAL)
response = test_client.get(ROUTER_SUBSCRIPTION_ENDPOINT) response = test_client.get(
ROUTER_SUBSCRIPTION_ENDPOINT, headers={"Authorization": "Bearer REALY_random_AND_3cure_T0keN"}
)
assert response.status_code == 200 assert response.status_code == 200
assert len(response.json()) == 3 assert len(response.json()) == 3
def test_router_subscriptions_endpoint_with_invalid_api_key(test_client, nokia_router_subscription_factory):
response = test_client.get(ROUTER_SUBSCRIPTION_ENDPOINT, headers={"Authorization": "Bearer fake_invalid_api_key"})
assert response.status_code == 403
assert response.json() == {"detail": "Invalid API Key"}
def test_router_subscriptions_endpoint_without_api_key(test_client, nokia_router_subscription_factory):
response = test_client.get(ROUTER_SUBSCRIPTION_ENDPOINT)
assert response.status_code == 403
assert response.json() == {"detail": "Not authenticated"}
...@@ -204,6 +204,10 @@ def configuration_data() -> dict: ...@@ -204,6 +204,10 @@ def configuration_data() -> dict:
"result_backend": "rpc://localhost:6379/0", "result_backend": "rpc://localhost:6379/0",
"result_expires": 3600, "result_expires": 3600,
}, },
"THIRD_PARTY_API_KEYS": {
"AnsibleDynamicInventoryGenerator": "REALY_random_AND_3cure_T0keN",
"Application_2": "another_REALY_random_AND_3cure_T0keN",
},
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment