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

Finished release 2.15.

parents 3eb75767 03879d73
No related branches found
Tags 2.15
No related merge requests found
Pipeline #89341 passed
......@@ -47,7 +47,7 @@ run-tox-pipeline:
sonarqube:
stage: sonarqube
image: sonarsource/sonar-scanner-cli
image: sonarsource/sonar-scanner-cli:10.0
script:
- sonar-scanner -Dsonar.login=$SONAR_TOKEN -Dproject.settings=./sonar.properties
tags:
......
# Changelog
## [2.15] - 2024-09-30
- Show current license usage when updating Kentik license of a router
- Fix the bug of clearing all the AE members and creating new objects instead of updating it.
- make orchestrator-core==2.7.5
## [2.14] - 2024-09-19
- Fixes to Infoblox client.
......
......@@ -109,7 +109,42 @@ class KentikClient:
return {}
def get_plans(self) -> list[dict[str, Any]]:
"""Get all Kentik plans available."""
"""Get all Kentik plans available.
Returns a list of ``plans`` that each have the following shape:
.. vale off
.. code-block:: json
"plan": {
"active": true,
"bgp_enabled": true,
"cdate" "1970-01-01T01:01:01.000Z",
"company_id": 111111,
"description": "A description of this plan",
"deviceTypes": [
{"device_type": "router"},
{"device_type": "host-nprobe-dns-www"}
],
"devices": [
{
"id": "111111",
"device_name": "rt0.city.tld.internal",
"device_type": "router"
},
],
"edate": "2999-01-01T09:09:09.000Z",
"fast_retention": 10,
"full_retention": 5,
"id": 11111,
"max_bigdata_fps": 100,
"max_devices": 9001,
"max_fps": 200,
"name": "KENTIK-PLAN-01",
"metadata": {},
}
.. vale on
"""
return self._send_request("GET", "v5/plans")["plans"]
def get_plan(self, plan_id: int) -> dict[str, Any]:
......
......@@ -60,6 +60,7 @@ def execute_playbook(
For example, an inventory consisting of two hosts, which each a unique host variable assigned to them looks as
follows:
.. vale off
.. code-block:: json
"inventory": {
......@@ -74,6 +75,7 @@ def execute_playbook(
}
}
}
.. vale on
.. warning::
Note the fact that the collection of all hosts is a dictionary, and not a list of strings. Ansible expects each
......
......@@ -216,6 +216,29 @@ def check_ip_trunk_lldp(subscription: Iptrunk, callback_route: str) -> State:
return {"subscription": subscription}
def update_side_members(subscription: Iptrunk, side_index: int, new_members: list[dict]) -> None:
"""Update the AE members for a given side without removing unchanged members."""
# Prepare a dictionary for quick lookup of existing members by name
current_members = subscription.iptrunk.iptrunk_sides[side_index].iptrunk_side_ae_members
existing_members_dict = {member.interface_name: member for member in current_members}
# Iterate over new members and update or add them
for new_member in new_members:
interface_name = new_member["interface_name"]
if interface_name in existing_members_dict:
# Member exists, update details but keep the same subscription ID
existing_member = existing_members_dict[interface_name]
existing_member.interface_description = new_member["interface_description"]
else:
# New member, create a new subscription ID
current_members.append(IptrunkInterfaceBlock.new(subscription_id=uuid4(), **new_member))
# Remove members that are no longer in the new members list
subscription.iptrunk.iptrunk_sides[side_index].iptrunk_side_ae_members = [
member for member in current_members if member.interface_name in [m["interface_name"] for m in new_members]
]
@step("Update subscription")
def modify_iptrunk_subscription(
subscription: Iptrunk,
......@@ -242,12 +265,16 @@ def modify_iptrunk_subscription(
for side in subscription.iptrunk.iptrunk_sides
]
removed_ae_members = []
# Compare previous and current members to determine which ones were removed
for side_index in range(2):
previous_members = previous_ae_members[side_index]
current_members = side_a_ae_members if side_index == 0 else side_b_ae_members
removed_ae_members.append([ae_member for ae_member in previous_members if ae_member not in current_members])
removed_ae_members.append([
ae_member
for ae_member in previous_members
if ae_member["interface_name"] not in [m["interface_name"] for m in current_members]
])
# Update the subscription
subscription.iptrunk.geant_s_sid = geant_s_sid
subscription.iptrunk.iptrunk_description = iptrunk_description
subscription.iptrunk.iptrunk_type = iptrunk_type
......@@ -255,20 +282,9 @@ def modify_iptrunk_subscription(
subscription.iptrunk.iptrunk_minimum_links = iptrunk_minimum_links
subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_geant_a_sid = side_a_ae_geant_a_sid
# Flush the old list of member interfaces
subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members.clear()
# And update the list to only include the new member interfaces
for member in side_a_ae_members:
subscription.iptrunk.iptrunk_sides[0].iptrunk_side_ae_members.append(
IptrunkInterfaceBlock.new(subscription_id=uuid4(), **member),
)
update_side_members(subscription, 0, side_a_ae_members)
subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_geant_a_sid = side_b_ae_geant_a_sid
subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members.clear()
for member in side_b_ae_members:
subscription.iptrunk.iptrunk_sides[1].iptrunk_side_ae_members.append(
IptrunkInterfaceBlock.new(subscription_id=uuid4(), **member),
)
update_side_members(subscription, 1, side_b_ae_members)
side_names = sorted([
subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_site.site_name,
......
......@@ -22,7 +22,11 @@ logger = logging.getLogger()
def _initial_input_form(subscription_id: UUIDstr) -> FormGenerator:
router = Router.from_subscription(subscription_id)
active_kentik_plans = {str(plan["id"]): plan["name"] for plan in KentikClient().get_plans() if plan["active"]}
active_kentik_plans = {
str(plan["id"]): f"{plan["name"]} - ({len(plan["devices"])}/{plan["max_devices"]})"
for plan in KentikClient().get_plans()
if plan["active"]
}
available_kentik_plans = Choice(
"Select a Kentik license",
zip(active_kentik_plans.keys(), active_kentik_plans.items(), strict=True), # type: ignore[arg-type]
......
orchestrator-core==2.7.4
orchestrator-core==2.7.5
requests==2.31.0
infoblox-client~=0.6.0
pycountry==23.12.11
......
......@@ -4,14 +4,14 @@ from setuptools import find_packages, setup
setup(
name="geant-service-orchestrator",
version="2.14",
version="2.15",
author="GÉANT Orchestration and Automation Team",
author_email="goat@geant.org",
description="GÉANT Service Orchestrator",
url="https://gitlab.software.geant.org/goat/gap/geant-service-orchestrator",
packages=find_packages(),
install_requires=[
"orchestrator-core==2.7.4",
"orchestrator-core==2.7.5",
"requests==2.31.0",
"infoblox-client~=0.6.0",
"pycountry==23.12.11",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment