diff --git a/build-docs.sh b/build-docs.sh index 796180f9f17a5fc539e71fe4772572fbe51a68fb..6c378580afa7f53e96def3313228d4f5f91ca009 100755 --- a/build-docs.sh +++ b/build-docs.sh @@ -1,5 +1,6 @@ python docs/dump-openapi-spec.py +rm -r ./docs/build/* sphinx-apidoc lso lso/app.py -o docs/source -d 2 -f vale --config=docs/vale/.vale.ini sync vale --config=docs/vale/.vale.ini docs/source/*.rst lso/*.py diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css new file mode 100644 index 0000000000000000000000000000000000000000..af9611171b13d53584f414daf47c984b07f84719 --- /dev/null +++ b/docs/source/_static/custom.css @@ -0,0 +1,13 @@ +.wy-menu > p > span { + color: rgb(237 21 86); +} + +section > dl > .sig-object { + background: #e5e8e8 !important; + color: rgb(237 21 86) !important; + border-top: 3px solid rgb(167 179 180) !important; +} + +.code.literal { + color: rgb(226 67 1) !important; +} diff --git a/docs/source/_static/geant_logo_white.svg b/docs/source/_static/geant_logo_white.svg new file mode 100644 index 0000000000000000000000000000000000000000..31bfead62b052812096b5a9c79cf782ce330a87c --- /dev/null +++ b/docs/source/_static/geant_logo_white.svg @@ -0,0 +1,16 @@ +<svg width="79" height="35" viewBox="0 0 79 35" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_101_15)"> +<path d="M15.9 17.8C16.5 17.3 17 17.1 17.4 17.1C18.4 17.1 18.7 17.8 18.7 18.2C18.5 18.3 14.2 19.7 14 19.8C13.9 19.7 13.9 19.6 13.8 19.6C14 19.4 15.9 17.8 15.9 17.8Z" fill="white" fill-opacity="0.85"/> +<path d="M0 27C0 31.8 2.1 34.3 6.3 34.3C9.1 34.3 10.8 33.1 10.8 33L10.9 32.9V26.2H5.2V28.1C5.2 28.1 8.1 28.1 8.6 28.1C8.6 28.6 8.6 31.6 8.6 31.9C8.3 32.1 7.4 32.4 6.2 32.4C3.7 32.4 2.5 30.6 2.5 27C2.5 24.9 3.1 22.4 5.9 22.4C7.8 22.4 8.5 23.5 8.5 24.5V24.8H11.1V24.5C11.1 22.1 9 20.5 5.9 20.5C2.2 20.5 0 22.9 0 27Z" fill="white" fill-opacity="0.85"/> +<path d="M20.2 20.7H12.6V34.1H20.7V32.2C20.7 32.2 15.5 32.2 14.9 32.2C14.9 31.7 14.9 28.5 14.9 28C15.5 28 20.2 28 20.2 28V26.1C20.2 26.1 15.5 26.1 14.9 26.1C14.9 25.6 14.9 23 14.9 22.5C15.5 22.5 20.5 22.5 20.5 22.5V20.6H20.2V20.7Z" fill="white" fill-opacity="0.85"/> +<path d="M54.5 20.7H42.9C42.9 20.7 42.9 28.7 42.9 30.6C42 29 37.2 20.7 37.2 20.7H34.5V34.1H36.8C36.8 34.1 36.8 26.1 36.8 24.2C37.7 25.8 42.5 34.1 42.5 34.1H45.2C45.2 34.1 45.2 23.2 45.2 22.6C45.7 22.6 48.4 22.6 48.9 22.6C48.9 23.2 48.9 34.1 48.9 34.1H51.3C51.3 34.1 51.3 23.2 51.3 22.6C51.8 22.6 54.9 22.6 54.9 22.6V20.7H54.5V20.7Z" fill="white" fill-opacity="0.85"/> +<path d="M28.9 20.7H28.7H26.4L21.4 34.1H23.8C23.8 34.1 25.1 30.6 25.3 30.2C25.7 30.2 29.8 30.2 30.2 30.2C30.3 30.6 31.7 34.1 31.7 34.1H34L28.9 20.7ZM25.9 28.3C26.1 27.6 27.3 24.4 27.7 23.3C28.1 24.4 29.2 27.6 29.5 28.3C28.7 28.3 26.6 28.3 25.9 28.3Z" fill="white" fill-opacity="0.85"/> +<path d="M77 8C68.2 -2.9 32.6 12.5 23 16.5C22.3 16.8 21.4 16.7 20.9 15.7C21.3 16.7 22.1 17.1 23.1 16.7C35.8 11.6 66.5 0.600002 74.2 10.7C77.7 15.3 76.7 20.9 72.9 28.8C72.7 29.1 72.6 29.4 72.6 29.4C72.6 29.4 72.6 29.4 72.6 29.5C72.6 29.5 72.6 29.5 72.6 29.6C72.3 30.1 71.9 30.3 71.6 30.4C72 30.4 72.5 30.2 72.9 29.6C73 29.5 73.1 29.3 73.3 29C78.7 19.5 80.7 12.5 77 8Z" fill="white" fill-opacity="0.85"/> +<path d="M70.3 29.9C70.2 29.8 68.6 28.4 67 26.9C58.7 19 33.4 -5.3 22.4 1.1C19.3 2.9 18.8 8.2 20.7 15.2C20.7 15.3 20.8 15.4 20.8 15.5C21 16.2 21.5 16.7 22.2 16.7C21.7 16.6 21.3 16.2 21.1 15.7C21.1 15.6 21 15.5 21 15.5C21 15.4 20.9 15.3 20.9 15.1C20.9 15 20.9 14.9 20.8 14.9C19.8 9 21 5.1 23.4 3.5C32.3 -2.5 53.5 15.8 64.2 25C66.6 27.1 69.4 29.5 70.2 30.1C71.4 31 72.4 30 72.7 29.5C72.3 30.1 71.3 30.7 70.3 29.9Z" fill="white" fill-opacity="0.85"/> +</g> +<defs> +<clipPath id="clip0_101_15"> +<rect width="78.9" height="34.3" fill="white"/> +</clipPath> +</defs> +</svg> diff --git a/docs/source/conf.py b/docs/source/conf.py index b499e94afbc69c650f0c03b17e7fd37d4b0597ea..e5cf04f14f1a37629aaea48e221aba4c40fc0cb1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -48,7 +48,7 @@ def setup(app): # -- Project information ----------------------------------------------------- -project = 'Lightweight Ansible Runner Provisioner' +project = 'Lightweight Service Orchestrator' copyright = '2023, GÉANT' author = 'GÉANT Orchestration & Automation Team' @@ -68,6 +68,12 @@ exclude_patterns = [] html_theme = 'sphinx_rtd_theme' html_static_path = ['_static'] +html_theme_options = { + 'style_nav_header_background': 'rgb(0 63 95)', +} +html_css_files = ['custom.css'] +html_logo = '_static/geant_logo_white.svg' + # Both the class' and the __init__ method's docstring # are concatenated and inserted. diff --git a/lso/routes/device.py b/lso/routes/device.py index f97766f96ab1494c71deac2a67469c01f3a10bc0..a7bda43b1d0d61027b8336c843069a2f0d9822e7 100644 --- a/lso/routes/device.py +++ b/lso/routes/device.py @@ -45,7 +45,7 @@ async def provision_node(params: NodeProvisioningParams) \ :param params: Parameters for provisioning a new node :type params: :class:`NodeProvisioningParams` :return: Response from the Ansible runner, including a run ID. - :rtype: :class:`PlaybookLaunchResponse` + :rtype: :class:`lso.playbook.PlaybookLaunchResponse` """ extra_vars = { 'wfo_device_json': params.subscription, diff --git a/lso/routes/ip_trunk.py b/lso/routes/ip_trunk.py index 5c90346312837ab50ca823b6c324607268051fda..bab6cf6bc50f4898246a058d8113d55d5308b74b 100644 --- a/lso/routes/ip_trunk.py +++ b/lso/routes/ip_trunk.py @@ -16,32 +16,48 @@ config_params = config.load() class IPTrunkParams(BaseModel): """Default parameters for an IPtrunk deployment.""" + #: The address where LSO should call back to upon completion. callback: HttpUrl + #: A dictionary representation of the IP trunk + #: subscription that is to be provisioned. subscription: dict class IPTrunkProvisioningParams(IPTrunkParams): """Additional parameters for provisioning an IPtrunk.""" + #: Whether this playbook execution should be a dry run, or run for real. + #: defaults to ``True`` for obvious reasons, also making it an optional + #: parameter. dry_run: Optional[bool] = True + #: The type of object that is changed. object: str class IPTrunkModifyParams(IPTrunkParams): """Additional parameters for modifying an IPtrunk.""" + #: Whether this playbook execution should be a dry run, or run for real. + #: defaults to ``True`` for obvious reasons, also making it an optional + #: parameter. dry_run: Optional[bool] = True + #: The old subscription object, represented as a dictionary. This allows + #: for calculating the difference in subscriptions. old_subscription: dict - verb: str + #: The type of object that is changed. + object: str class IPTrunkCheckParams(IPTrunkParams): """Additional parameters for checking an IPtrunk.""" + #: The name of the check that is to be performed. check_name: str class IPTrunkDeleteParams(IPTrunkParams): """Additional parameters for deleting an IPtrunk.""" + #: Whether this playbook execution should be a dry run, or run for real. + #: defaults to ``True`` for obvious reasons, also making it an optional + #: parameter. dry_run: Optional[bool] = True - verb: str @router.post('/') @@ -50,6 +66,12 @@ def provision_ip_trunk(params: IPTrunkProvisioningParams) \ """ Launch a playbook to provision a new IP trunk service. The response will contain either a job ID, or error information. + + :param params: The parameters that define the new subscription object that + is to be deployed. + :type params: :class:`IPTrunkProvisioningParams` + :return: Response from the Ansible runner, including a run ID. + :rtype: :class:`lso.playbook.PlaybookLaunchResponse` """ extra_vars = { 'wfo_trunk_json': params.subscription, @@ -78,21 +100,31 @@ def provision_ip_trunk(params: IPTrunkProvisioningParams) \ def modify_ip_trunk(params: IPTrunkModifyParams) -> PlaybookLaunchResponse: """ Launch a playbook that modifies an existing IP trunk service. + + :param params: The parameters that define the change in configuration. + :type params: :class:`IPTrunkModifyParams` + :return: Response from the Ansible runner, including a run ID. + :rtype: :class:`lso.playbook.PlaybookLaunchResponse` """ extra_vars = { - 'wfo_ip_trunk_json': params.subscription, - 'wfo_old_ip_trunk_json': params.old_subscription, + 'wfo_trunk_json': params.subscription, + 'old_wfo_trunk_json': params.old_subscription, 'dry_run': str(params.dry_run), - 'verb': params.verb + 'verb': 'modify', + 'config_object': params.object, + 'commit_comment': f'IPtrunk ' + f"{params.subscription['iptrunk']['geant_s_sid']} " + f"({params.subscription['subscription_id']}) - " + f'modification of {params.object}' } return run_playbook( playbook_path=path.join(config_params.ansible_playbooks_root_dir, 'iptrunks.yaml'), - inventory=[params.subscription['iptrunk']['iptrunk_sideA_node'][ - 'device_fqdn'], - params.subscription['iptrunk']['iptrunk_sideB_node'][ - 'device_fqdn']], + inventory=str(params.subscription['iptrunk']['iptrunk_sideA_node'][ + 'device_fqdn'] + "\n" + + params.subscription['iptrunk']['iptrunk_sideB_node'][ + 'device_fqdn'] + "\n"), extra_vars=extra_vars, callback=params.callback ) @@ -102,11 +134,17 @@ def modify_ip_trunk(params: IPTrunkModifyParams) -> PlaybookLaunchResponse: def delete_ip_trunk(params: IPTrunkDeleteParams) -> PlaybookLaunchResponse: """ Launch a playbook that deletes an existing IP trunk service. + + :param params: Parameters that define the subscription that should get + terminated. + :type params: :class:`IPTrunkDeleteParams` + :return: Response from the Ansible runner, including a run ID. + :rtype: :class:`lso.playbook.PlaybookLaunchResponse` """ extra_vars = { 'wfo_trunk_json': params.subscription, 'dry_run': str(params.dry_run), - 'verb': params.verb, + 'verb': 'terminate', 'config_object': "trunk_deprovision", 'commit_comment': f'IPtrunk ' f"{params.subscription['iptrunk']['geant_s_sid']} " @@ -130,6 +168,12 @@ def delete_ip_trunk(params: IPTrunkDeleteParams) -> PlaybookLaunchResponse: def check_ip_trunk(params: IPTrunkCheckParams) -> PlaybookLaunchResponse: """ Launch a playbook that performs a check on an IP trunk service instance. + + :param params: Parameters that define the check that is going to be + executed, including on which relevant subscription. + :type params: :class:`IPTrunkCheckParams` + :return: Response from the Ansible runner, including a run ID. + :rtype: :class:`lso.playbook.PlaybookLaunchResponse` """ extra_vars = { 'wfo_ip_trunk_json': params.subscription,