Skip to content
Snippets Groups Projects
Commit 3fe41c67 authored by Hakan Calim's avatar Hakan Calim
Browse files

NAT-286: merged from develop

parents f0774e61 af39ed7c
Branches
Tags
1 merge request!89Feature/nat 286 create unit tests for netbox client
Pipeline #84241 failed
Showing
with 213 additions and 106 deletions
``gso.workflows.iptrunk.utils``
===============================
.. automodule:: gso.workflows.iptrunk.utils
:members:
:show-inheritance:
``gso.workflows.router.create_router``
======================================
.. automodule:: gso.workflows.router.create_router
:members:
:show-inheritance:
``gso.workflows.router``
========================
.. automodule:: gso.workflows.router
:members:
:show-inheritance:
Submodules
----------
.. toctree::
:maxdepth: 2
:titlesonly:
create_router
terminate_router
``gso.workflows.router.terminate_router``
=========================================
.. automodule:: gso.workflows.router.terminate_router
:members:
:show-inheritance:
``gso.workflows.site.create_site``
==================================
.. automodule:: gso.workflows.site.create_site
:members:
:show-inheritance:
``gso.workflows.site``
======================
.. automodule:: gso.workflows.site
:members:
:show-inheritance:
Submodules
----------
.. toctree::
:maxdepth: 2
:titlesonly:
create_site
``gso.workflows.tasks.import_iptrunk``
======================================
.. automodule:: gso.workflows.tasks.import_iptrunk
:members:
:show-inheritance:
``gso.workflows.tasks.import_router``
=====================================
.. automodule:: gso.workflows.tasks.import_router
:members:
:show-inheritance:
``gso.workflows.tasks.import_site``
===================================
.. automodule:: gso.workflows.tasks.import_site
:members:
:show-inheritance:
``gso.workflows.tasks``
=======================
.. automodule:: gso.workflows.tasks
:members:
:show-inheritance:
Submodules
----------
.. toctree::
:maxdepth: 2
:titlesonly:
import_iptrunk
import_router
import_site
``gso.workflows.utils``
=======================
.. automodule:: gso.workflows.utils
:members:
:show-inheritance:
=========================
Sub-packages and -modules
=========================
This page lists references to the documentation of all sub-packages and -modules that make up :term:`GSO`.
Subpackages
-----------
.. toctree::
:maxdepth: 2
:titlesonly:
module/api/index
module/cli/index
module/products/index
module/schemas/index
module/services/index
module/utils/index
module/workflows/index
Submodules
----------
``gso.settings`` module
^^^^^^^^^^^^^^^^^^^^^^^
.. automodule:: gso.settings
:members:
:undoc-members:
:show-inheritance:
# Quickstart
## Development environment and dependencies
- Install python 3.10 if you don't have it already:
- ``add-apt-repository ppa:deadsnakes/ppa``
- ``apt install python3.10 python3.10-distutils``
- Follow Steps 1 and 2 from here to install dependencies and setup DB: https://workfloworchestrator.org/orchestrator-core/workshops/beginner/debian/
- To install the orchestrator GUI, you can follow the steps 5 and 6 from the previous link.
- Create a virtual environment:
- ``source /usr/share/virtualenvwrapper/virtualenvwrapper.sh``
- ``mkvirtualenv --python python3.10 gso``
- To use the virtual environment:
- `source /usr/share/virtualenvwrapper/virtualenvwrapper.sh`
- `workon gso`
## Installation
Do all this inside the virtual environment.
- Clone this repository and ``cd`` into it
- ``pip install -r requirements.txt``
- If you get an error because you pip version is too old, run this: `curl -sS https://bootstrap.pypa.io/get-pip.py | python3.10`
- ``pip install -e .``
- `cd` into `gso` directory and create ``oss-params.json`` based on the ``oss-params-example.json`` file.
- Export the oss-params file: ``export OSS_PARAMS_FILENAME="/path/to/oss-params.json"``
- Upgrade DB to latest revision: `PYTHONPATH=. python main.py db upgrade heads`
## Run
- Start the workflow orchestrator core with ``uvicorn --host 0.0.0.0 --port 8080 main:app`` from inside the ``gso`` directory of this repository.
- Start the GUI with ``yarn start``.
## Useful workflow orchestrator resources
- WFO API (Swagger): <https://workfloworchestrator.org/orchestrator-core/architecture/application/api/>
- WFO API (repository): <https://github.com/workfloworchestrator/orchestrator-core/tree/main/orchestrator/api/api_v1/endpoints>
- Carolina's notes: <https://wiki.geant.org/pages/viewpage.action?pageId=562921625>
### API examples
*Note: update IP address in the request to your own where you're running WFO.*
**Creating subscriptions** (look at the `initial_input_form_generator` method of the workflow to find what properties need to be in the body of the POST request)
Create process that produces a new subscription (CREATE workflow)
``curl -X POST -H "Content-Type: application/json" http://10.98.1.62:8080/api/processes/create_trunk --data '[{"product": "321045fc-21ec-476b-b67b-5f211e47c3d7"},{"trunk_name": "mytrunkfromapi", "geant_s_sid": "a1b2c3"}]'``
Create process that manipulates the state of a subscription (TERMINATE workflow)
``curl -X POST -H "Content-Type: application/json" http://10.98.1.62:8080/api/processes/terminate_trunk --data '[{"subscription_id": "910e7044-c427-46d1-afc3-7817e221d45d"}, {"are_you_sure": "yes"}]'``
**Deleting subscriptions** (not the same as running a TERMINATE workflow for a subscription, but to actually erase it from the WFO database)
To do this, you first have to delete the processes first:
``curl -X 'DELETE' 'http://10.98.1.62:8080/api/processes/7447a3e9-7c58-4ae7-8804-c0a75c39c924'``
Delete a subscription:
``curl -X 'DELETE' 'http://10.98.1.62:8080/api/subscriptions/3f16532b-0a48-4fe3-802a-36b3f54eed0e'``
Quickstart
==========
Development environment and dependencies
----------------------------------------
- Install python 3.10 if you do not have it already:
- ``add-apt-repository ppa:deadsnakes/ppa``
- ``apt install python3.10 python3.10-distutils``
- Follow Steps 1 and 2 from here to install dependencies and setup DB:
`<https://workfloworchestrator.org/orchestrator-core/workshops/beginner/debian/>`_
- To install the orchestrator GUI, you can follow the steps 5 and 6 from the previous link.
- Create a virtual environment:
- ``source /usr/share/virtualenvwrapper/virtualenvwrapper.sh``
- ``mkvirtualenv --python python3.10 gso``
- To use the virtual environment:
- ``source /usr/share/virtualenvwrapper/virtualenvwrapper.sh``
- ``workon gso``
Installation
------------
Do all this inside the virtual environment.
- Clone this repository
- ``pip install -r requirements.txt``
- If you get an error because you pip version is too old, run this:
``curl -sS https://bootstrap.pypa.io/get-pip.py | python3.10``
- ``pip install -e .``
- Create an ``oss-params.json`` based on the ``oss-params-example.json`` file inside ``/gso``.
- Export the oss-params file: ``export OSS_PARAMS_FILENAME="/path/to/oss-params.json"``
- Upgrade DB to latest revision: ``PYTHONPATH=. python main.py db upgrade heads``
Run
---
- Start the workflow orchestrator core with ``uvicorn --host 0.0.0.0 --port 8080 main:app`` from inside the ``gso``
directory of this repository.
- Start the GUI with ``yarn start``.
Useful workflow orchestrator resources
--------------------------------------
- WFO API (Swagger): `<https://workfloworchestrator.org/orchestrator-core/architecture/application/api/>`_
- WFO API (repository):
`<https://github.com/workfloworchestrator/orchestrator-core/tree/main/orchestrator/api/api_v1/endpoints>`_
$(document).ready(function () {
$('a.external').attr('target', '_blank');
});
...@@ -6,8 +6,8 @@ Vocab = geant-jargon, Sphinx ...@@ -6,8 +6,8 @@ Vocab = geant-jargon, Sphinx
Packages = proselint, Microsoft Packages = proselint, Microsoft
[*.{md,py}] [*.{py,rst}]
; We only lint .md and .py files ; We only lint .rst and .py files
BasedOnStyles = Vale, proselint, Microsoft BasedOnStyles = Vale, proselint, Microsoft
; Some headers are generated and we have no real influence over them ; Some headers are generated and we have no real influence over them
Microsoft.Headings = NO Microsoft.Headings = NO
...@@ -22,10 +22,13 @@ proselint.Typography = warning ...@@ -22,10 +22,13 @@ proselint.Typography = warning
; Same applies for not using contractions ; Same applies for not using contractions
Microsoft.Contractions = NO Microsoft.Contractions = NO
custom.Contractions = YES custom.Contractions = YES
; Using a "regular" - instead of an en dash is totally fine
Microsoft.Negative = NO
Microsoft.RangeFormat = NO
TokenIgnores = ({term}), (:param \S+:), (:type \S+:) TokenIgnores = (:term:`\S+`), (:param \S+(?: \S+)?:), (:type \S+:), (:return \S+:), (:rtype: \S+), (:class:`\S+`)
[*/glossary.md] [*/glossary.rst]
; Ignore acronyms being undefined in the file that defines all acronyms by definition. ; Ignore acronyms being undefined in the file that defines all acronyms by definition.
Microsoft.Acronyms = NO Microsoft.Acronyms = NO
Microsoft.Contractions = NO Microsoft.Contractions = NO
...@@ -33,4 +36,4 @@ custom.Contractions = YES ...@@ -33,4 +36,4 @@ custom.Contractions = YES
Microsoft.Passive = NO Microsoft.Passive = NO
[formats] [formats]
py = md py = rst
from typing import Any, Dict from typing import Any
from uuid import UUID from uuid import UUID
from fastapi import Depends, HTTPException, status from fastapi import Depends, HTTPException, status
...@@ -30,20 +30,16 @@ def _start_process(process_name: str, data: dict) -> UUID: ...@@ -30,20 +30,16 @@ def _start_process(process_name: str, data: dict) -> UUID:
@router.post("/sites", status_code=status.HTTP_201_CREATED, response_model=ImportResponseModel) @router.post("/sites", status_code=status.HTTP_201_CREATED, response_model=ImportResponseModel)
def import_site(site: SiteImportModel) -> Dict[str, Any]: def import_site(site: SiteImportModel) -> dict[str, Any]:
"""Import a site by running the import_site workflow. """Import a site by running the import_site workflow.
Args: :param site: The site information to be imported.
---- :type site: SiteImportModel
site (SiteImportModel): The site information to be imported.
Returns: :return: A dictionary containing the process id of the started process and detail message.
------- :rtype: dict[str, Any]
dict: A dictionary containing the process id of the started process and detail message.
Raises: :raises HTTPException: If the site already exists or if there's an error in the process.
------
HTTPException: If the site already exists or if there's an error in the process.
""" """
try: try:
subscription = subscriptions.retrieve_subscription_by_subscription_instance_value( subscription = subscriptions.retrieve_subscription_by_subscription_instance_value(
...@@ -59,20 +55,16 @@ def import_site(site: SiteImportModel) -> Dict[str, Any]: ...@@ -59,20 +55,16 @@ def import_site(site: SiteImportModel) -> Dict[str, Any]:
@router.post("/routers", status_code=status.HTTP_201_CREATED, response_model=ImportResponseModel) @router.post("/routers", status_code=status.HTTP_201_CREATED, response_model=ImportResponseModel)
def import_router(router_data: RouterImportModel) -> Dict[str, Any]: def import_router(router_data: RouterImportModel) -> dict[str, Any]:
"""Import a router by running the import_router workflow. """Import a router by running the import_router workflow.
Args: :param router_data: The router information to be imported.
---- :type router_data: RouterImportModel
router_data (RouterImportModel): The router information to be imported.
Returns: :return: A dictionary containing the process id of the started process and detail message.
------- :rtype: dict[str, Any]
dict: A dictionary containing the process id of the started process and detail message.
Raises: :raises HTTPException: If there's an error in the process.
------
HTTPException: If there's an error in the process.
""" """
pid = _start_process("import_router", router_data.dict()) pid = _start_process("import_router", router_data.dict())
...@@ -80,20 +72,16 @@ def import_router(router_data: RouterImportModel) -> Dict[str, Any]: ...@@ -80,20 +72,16 @@ def import_router(router_data: RouterImportModel) -> Dict[str, Any]:
@router.post("/iptrunks", status_code=status.HTTP_201_CREATED, response_model=ImportResponseModel) @router.post("/iptrunks", status_code=status.HTTP_201_CREATED, response_model=ImportResponseModel)
def import_iptrunk(iptrunk_data: IptrunkImportModel) -> Dict[str, Any]: def import_iptrunk(iptrunk_data: IptrunkImportModel) -> dict[str, Any]:
"""Import an iptrunk by running the import_iptrunk workflow. """Import an iptrunk by running the import_iptrunk workflow.
Args: :param iptrunk_data: The iptrunk information to be imported.
---- :type iptrunk_data: IptrunkImportModel
iptrunk_data (IptrunkImportModel): The iptrunk information to be imported.
Returns: :return: A dictionary containing the process id of the started process and detail message.
------- :rtype: dict[str, Any]
dict: A dictionary containing the process id of the started process and detail message.
Raises: :raises HTTPException: If there's an error in the process.
------
HTTPException: If there's an error in the process.
""" """
pid = _start_process("import_iptrunk", iptrunk_data.dict()) pid = _start_process("import_iptrunk", iptrunk_data.dict())
......
import typer import typer
from pynetbox import RequestError from pynetbox import RequestError
from gso.services.netbox_client import NetBoxClient from gso.services.netbox_client import NetboxClient
from gso.utils.device_info import DEFAULT_SITE, ROUTER_ROLE
app: typer.Typer = typer.Typer() app: typer.Typer = typer.Typer()
...@@ -11,24 +12,24 @@ def netbox_initial_setup() -> None: ...@@ -11,24 +12,24 @@ def netbox_initial_setup() -> None:
"""Set up NetBox for the first time. """Set up NetBox for the first time.
It includes: It includes:
- Creating a default site (GEANT) - Creating a default site (GÉANT)
- Creating device roles (Router) - Creating device roles (Router)
""" """
typer.echo("Initial setup of NetBox ...") typer.echo("Initial setup of NetBox ...")
typer.echo("Connecting to NetBox ...") typer.echo("Connecting to NetBox ...")
nbclient = NetBoxClient() nbclient = NetboxClient()
typer.echo("Creating GEANT site ...") typer.echo("Creating GÉANT site ...")
try: try:
nbclient.create_device_site("GEANT", "geant") nbclient.create_device_site(DEFAULT_SITE["name"], DEFAULT_SITE["slug"])
typer.echo("Site created successfully.") typer.echo("Site created successfully.")
except RequestError as e: except RequestError as e:
typer.echo(f"Error creating site: {e}") typer.echo(f"Error creating site: {e}")
typer.echo("Creating Router device role ...") typer.echo("Creating Router device role ...")
try: try:
nbclient.create_device_role("router", "router") nbclient.create_device_role(ROUTER_ROLE["name"], ROUTER_ROLE["slug"])
typer.echo("Device role created successfully.") typer.echo("Device role created successfully.")
except RequestError as e: except RequestError as e:
typer.echo(f"Error creating device role: {e}") typer.echo(f"Error creating device role: {e}")
......
"""The main module that runs {term}`GSO`.""" """The main module that runs :term:`GSO`."""
import typer import typer
from orchestrator import OrchestratorCore from orchestrator import OrchestratorCore
from orchestrator.cli.main import app as core_cli from orchestrator.cli.main import app as core_cli
......
"""Module that updates the domain model of {term}`GSO`. Should contain all types of subscriptions.""" """Module that updates the domain model of :term:`GSO`. Should contain all types of subscriptions."""
from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY
from gso.products.product_types.iptrunk import Iptrunk from gso.products.product_types.iptrunk import Iptrunk
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment