diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/client.py b/common/client.py similarity index 98% rename from src/client.py rename to common/client.py index 5b1dfff..f9a15bc 100644 --- a/src/client.py +++ b/common/client.py @@ -3,7 +3,7 @@ import httpx from pydantic import BaseModel -from pydantic_eda.core import ( +from pydantic_eda.core.v25_4_1.models import ( GroupVersionKind, NsCrGvkName, Transaction, @@ -44,7 +44,7 @@ def __init__(self, base_url: str): self.transaction: Optional[Transaction] = None self.transaction_endpoint: str = self.base_url.join("/core/transaction/v1") - super().__init__(headers=self.headers, verify=False) + super().__init__(headers=self.headers, verify=False, timeout=300) # acquire the token during initialization self.auth() diff --git a/src/logging.py b/common/logging.py similarity index 100% rename from src/logging.py rename to common/logging.py diff --git a/src/banner.py b/eda_client/banner.py similarity index 100% rename from src/banner.py rename to eda_client/banner.py diff --git a/src/interface.py b/eda_client/interface.py similarity index 100% rename from src/interface.py rename to eda_client/interface.py diff --git a/examples/005-banner/main.py b/examples/005-banner/main.py new file mode 100644 index 0000000..5bf26da --- /dev/null +++ b/examples/005-banner/main.py @@ -0,0 +1,39 @@ +import os +import sys + +sys.path.append( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +) + +import pydantic_eda.apps.siteinfo.v1alpha1.models as siteinfo + +from common.client import EDAClient +from common.logging import setup_logging + +setup_logging() + +NS = "eda" + + +def main(): + eda = EDAClient(base_url="https://devbox.netdevops.me:9444") + + my_banner = siteinfo.Banner( + apiVersion="siteinfo.eda.nokia.com/v1alpha1", + kind="Banner", + metadata=siteinfo.BannerMetadata( + namespace=NS, + name="my-banner", + ), + spec=siteinfo.BannerSpec( + loginBanner="Pydantic EDA says Hi", + nodes=["leaf1"], + ), + ) + + eda.add_to_transaction_create(my_banner) + _ = eda.commit_transaction() + + +if __name__ == "__main__": + main() diff --git a/examples/020-many-vnets/main.py b/examples/020-many-vnets/main.py new file mode 100644 index 0000000..aa20808 --- /dev/null +++ b/examples/020-many-vnets/main.py @@ -0,0 +1,32 @@ +import os +import sys + +sys.path.append( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +) + +from vnet import virtualnetwork + +from common.client import EDAClient +from common.logging import setup_logging + +setup_logging() + +NS = "eda" + + +def main(): + num_vnets = 100 + + eda = EDAClient(base_url="https://1.dev.srexperts.net:9443") + + for i in range(num_vnets): + my_vnet = virtualnetwork(ns=NS, id=i) + + eda.add_to_transaction_create(my_vnet) + + _ = eda.commit_transaction() + + +if __name__ == "__main__": + main() diff --git a/examples/020-many-vnets/vnet.py b/examples/020-many-vnets/vnet.py new file mode 100644 index 0000000..af6dc59 --- /dev/null +++ b/examples/020-many-vnets/vnet.py @@ -0,0 +1,82 @@ +import pydantic_eda.apps.services.v1alpha1.models as service + + +def virtualnetwork(ns: str, id: int) -> service.VirtualNetwork: + router = service.VirtualNetworkSpecRouter( + name=f"vnet-router-{id}", + spec=service.VirtualNetworkSpecRouterSpec( + eviPool="evi-pool", + tunnelIndexPool="tunnel-index-pool", + type="EVPNVXLAN", + vniPool="vni-pool", + ), + ) + + bd = service.VirtualNetworkSpecBridgeDomain( + name=f"vnet-bridge-domain-{id}", + spec=service.VirtualNetworkSpecBridgeDomainSpec( + eviPool="evi-pool", + tunnelIndexPool="tunnel-index-pool", + type="EVPNVXLAN", + vniPool="vni-pool", + ), + ) + + vlan = service.VirtualNetworkSpecVlan( + name=f"vnet-vlan-{id}", + spec=service.VirtualNetworkSpecVlanSpec( + bridgeDomain=bd.name, + interfaceSelector=["edge-type=compute"], + uplink=service.VirtualNetworkSpecVlanSpecUplink(uplinkVLANID="pool"), + vlanID=str(300 + id), + ), + ) + + irb = service.VirtualNetworkSpecIrbInterface( + name=f"vnet-irb-{id}", + spec=service.VirtualNetworkSpecIrbInterfaceSpec( + bridgeDomain=bd.name, + hostRoutePopulate=service.VirtualNetworkSpecIrbInterfaceSpecHostRoutePopulate( + dynamic=True, static=True + ), + ipAddresses=[ + service.VirtualNetworkSpecIrbInterfaceSpecIpAddress( + ipv4Address=service.VirtualNetworkSpecIrbInterfaceSpecIpAddressIpv4Address( + ipPrefix="10.30.0.1/24", primary=True + ) + ), + service.VirtualNetworkSpecIrbInterfaceSpecIpAddress( + ipv6Address=service.VirtualNetworkSpecIrbInterfaceSpecIpAddressIpv6Address( + ipPrefix="fd00:fdfd:0:3000::1/64", primary=True + ) + ), + ], + router=router.name, + ), + ) + + vnet = service.VirtualNetwork( + apiVersion="services.eda.nokia.com/v1alpha1", + kind="VirtualNetwork", + metadata=service.VirtualNetworkMetadata( + name=f"vnet-api-example-{id}", + namespace=ns, + labels={"role": "pydantic-example"}, + ), + spec=service.VirtualNetworkSpec( + routers=[ + router, + ], + bridgeDomains=[ + bd, + ], + vlans=[ + vlan, + ], + irbInterfaces=[ + irb, + ], + ), + ) + + return vnet diff --git a/pyproject.toml b/pyproject.toml index c2f6f3e..e28fddc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,3 +13,8 @@ dependencies = [ [tool.uv.sources] pydantic-eda = { git = "https://github.com/eda-labs/pydantic-eda" } + +[tool.ruff.lint] +# do not warn about imports not at the top +# as we do have to modify the sys path for the exercises +ignore = ["E402"] diff --git a/uv.lock b/uv.lock index 62e21ce..8a9b673 100644 --- a/uv.lock +++ b/uv.lock @@ -12,47 +12,47 @@ wheels = [ [[package]] name = "anyio" -version = "4.8.0" +version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } +sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, + { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 }, ] [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.4.26" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, + { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618 }, ] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, ] [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, ] [[package]] @@ -174,8 +174,8 @@ wheels = [ [[package]] name = "pydantic-eda" -version = "0.1.0" -source = { git = "https://github.com/eda-labs/pydantic-eda#321aa02f167064bbd912eb32a1a4edc7a48345bc" } +version = "0.3.2" +source = { git = "https://github.com/eda-labs/pydantic-eda#6bc99584c5a2735d77c65f2a0a48c039e5e09773" } dependencies = [ { name = "pydantic" }, ] @@ -191,15 +191,15 @@ wheels = [ [[package]] name = "rich" -version = "13.9.4" +version = "14.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 }, ] [[package]] @@ -213,9 +213,9 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, + { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 }, ]