diff options
| author | Dimitri Staessens <dimitri@ouroboros.rocks> | 2026-03-07 23:04:29 +0100 |
|---|---|---|
| committer | Dimitri Staessens <dimitri@ouroboros.rocks> | 2026-03-08 14:25:09 +0100 |
| commit | 3ab851644501e4906e91084a81e33e1a3cebd5cc (patch) | |
| tree | 3c9132d16ac137ed34fd0daefe1fb18b8c15f814 | |
| parent | 6cbcfb039e608419bd6ced673723918aca6fb278 (diff) | |
| download | rumba-0.23.0.tar.gz rumba-0.23.0.zip | |
build: Move to pyproject + setuptools_scm0.23.0
Replace setup.py and MANIFEST.in with pyproject.toml. The version is
now derived from git tags via setuptools_scm, and added
.git_archival.txt and .gitattributes for git archive support. Remove
_version.py from version control as it is now auto-generated at build
time.
Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
| -rw-r--r-- | .git_archival.txt | 4 | ||||
| -rw-r--r-- | .gitattributes | 1 | ||||
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | MANIFEST.in | 3 | ||||
| -rw-r--r-- | README.md | 15 | ||||
| -rw-r--r-- | doc/conf.py | 7 | ||||
| -rw-r--r-- | pyproject.toml | 39 | ||||
| -rw-r--r-- | rumba/__init__.py | 3 | ||||
| -rw-r--r-- | rumba/_version.py | 28 | ||||
| -rw-r--r-- | rumba/irm_backend.py | 83 | ||||
| -rw-r--r-- | rumba/prototypes/ouroboros.py | 9 | ||||
| -rwxr-xr-x | setup.py | 53 |
12 files changed, 123 insertions, 125 deletions
diff --git a/.git_archival.txt b/.git_archival.txt new file mode 100644 index 0000000..3994ec0 --- /dev/null +++ b/.git_archival.txt @@ -0,0 +1,4 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true)$ +ref-names: $Format:%D$ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..00a7b00 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.git_archival.txt export-subst @@ -11,6 +11,9 @@ dist/ .eggs/ sdist/ +# setuptools_scm generated +rumba/_version.py + # Virtual environments .venv/ venv/ diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index b44eea6..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include AUTHORS -include LICENSE -include README.md @@ -24,6 +24,7 @@ pip install . Optional extras: ```bash +pip install rumba[docker] # Docker testbed backend pip install rumba[NumpyAcceleration] # faster random traffic generation pip install rumba[graphs] # PDF graph export via pydot pip install rumba[visualizer] # interactive visualization via igraph + plotly @@ -35,8 +36,7 @@ On Debian/Ubuntu you may also need: sudo apt-get install build-essential libssl-dev libffi-dev python3-dev ``` -The required dependencies (`paramiko` and `docker`) are installed -automatically. +The required dependency (`paramiko`) is installed automatically. ## Defining a Topology @@ -200,6 +200,17 @@ If you use Rumba in your research, please cite: > "Rumba: A Python framework for automating large-scale recursive > internet experiments on GENI and FIRE+," *IEEE*, 2018. +## Versioning + +Rumba uses `setuptools_scm` to derive its version from git tags. + +**Compatibility contract across Ouroboros repositories:** + +| Scope | Rule | +|---|---| +| ouroboros (C) ↔ pyouroboros / rumba | Shared `major.minor` — rumba requires at least the same ouroboros `major.minor` | +| pyouroboros ↔ rumba ↔ ouroboros-integration | Strict lockstep `major.minor.patch` — always released together | + ## License Rumba is licensed under the diff --git a/doc/conf.py b/doc/conf.py index 55e3572..7ea5303 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -20,10 +20,7 @@ autoclass_content = 'both' html_static_path = ['_static'] templates_path = ['_templates'] -_locals = {} -with open('../rumba/_version.py') as fp: - exec(fp.read(), None, _locals) -version = _locals['__version__'] +from rumba import __version__ +version = __version__ -version = version release = version diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b596afd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,39 @@ +[build-system] +requires = ["setuptools>=64", "setuptools_scm>=8"] +build-backend = "setuptools.build_meta" + +[project] +name = "Rumba" +dynamic = ["version"] +description = "Rumba measurement framework for Ouroboros" +readme = "README.md" +license = "LGPL-2.1-or-later" +requires-python = ">=3.8" +keywords = ["ouroboros", "measurement", "testbed"] +authors = [ + { name = "Sander Vrijders", email = "sander@ouroboros.rocks" }, + { name = "Dimitri Staessens", email = "dimitri@ouroboros.rocks" }, +] +dependencies = [ + "packaging", + "paramiko>=2.0,<4", +] + +[project.optional-dependencies] +docker = ["docker>=5.0,<8"] +NumpyAcceleration = ["numpy"] +graphs = ["pydot"] +visualizer = ["igraph", "plotly"] +pyouroboros = ["PyOuroboros"] + +[project.urls] +Homepage = "https://codeberg.org/o7s/rumba" + +[tool.setuptools] +script-files = ["tools/rumba-access"] + +[tool.setuptools.packages.find] +exclude = ["examples", "tools", "doc"] + +[tool.setuptools_scm] +version_file = "rumba/_version.py" diff --git a/rumba/__init__.py b/rumba/__init__.py index 62897b3..6ca82c1 100644 --- a/rumba/__init__.py +++ b/rumba/__init__.py @@ -23,3 +23,6 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., http://www.fsf.org/about/contact/. # + +from rumba._version import version as __version__ # noqa: F401 +from rumba._version import version_tuple as __version_tuple__ # noqa: F401 diff --git a/rumba/_version.py b/rumba/_version.py deleted file mode 100644 index f1e5b84..0000000 --- a/rumba/_version.py +++ /dev/null @@ -1,28 +0,0 @@ -# -# A library to manage ARCFIRE experiments -# -# Copyright (C) 2017-2018 Nextworks S.r.l. -# Copyright (C) 2017-2018 imec -# -# Sander Vrijders <sander.vrijders@ugent.be> -# Dimitri Staessens <dimitri.staessens@ugent.be> -# Vincenzo Maffione <v.maffione@nextworks.it> -# Marco Capitani <m.capitani@nextworks.it> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., http://www.fsf.org/about/contact/. -# - -__version_info__ = (0, 23, 0) -__version__ = '.'.join(map(str, __version_info__)) diff --git a/rumba/irm_backend.py b/rumba/irm_backend.py index e9cc5c6..e859e21 100644 --- a/rumba/irm_backend.py +++ b/rumba/irm_backend.py @@ -29,6 +29,8 @@ Provides two implementations: """ import abc +from packaging.version import Version + import rumba.log as log from rumba.elements.topology import LayerType @@ -220,26 +222,48 @@ class IrmPython(IrmBackend): def __init__(self): try: - from ouroboros import irm as _irm from ouroboros import cli as _cli - self._irm = _irm self._cli = _cli logger.info("pyouroboros IRM backend loaded successfully") except ImportError: raise ImportError( "pyouroboros is required for Python backend. " "Install it from the pyouroboros repository.") + self._check_version() + + @staticmethod + def _check_version(): + """Verify PyOuroboros is on the same patch level as Rumba. + + Uses PEP 440 ordering so that dev/pre-release versions sort + correctly: tag 0.23.0 accepts 0.23.1.dev0 (setuptools_scm's + representation of the first commit after 0.23.0) because + 0.23.0 <= 0.23.1.dev0 < 0.23.1 in PEP 440. + """ + import importlib.metadata + from rumba._version import version as rumba_ver + + pyouro_ver = Version(importlib.metadata.version("PyOuroboros")) + floor = Version(rumba_ver) + parts = [int(x) for x in rumba_ver.split(".")[:3]] + parts[2] += 1 + ceiling = Version(".".join(str(x) for x in parts)) + if pyouro_ver < floor or pyouro_ver >= ceiling: + raise RuntimeError( + "PyOuroboros >= %s, < %s required (lockstep with Rumba), " + "got %s" % (floor, ceiling, pyouro_ver) + ) def _get_ipcp_type(self, layer_type): """Convert LayerType to pyouroboros IpcpType.""" type_map = { - LayerType.LOCAL: self._irm.IpcpType.LOCAL, - LayerType.UNICAST: self._irm.IpcpType.UNICAST, - LayerType.BROADCAST: self._irm.IpcpType.BROADCAST, - LayerType.ETH_LLC: self._irm.IpcpType.ETH_LLC, - LayerType.ETH_DIX: self._irm.IpcpType.ETH_DIX, - LayerType.UDP4: self._irm.IpcpType.UDP4, - LayerType.UDP6: self._irm.IpcpType.UDP6, + LayerType.LOCAL: self._cli.IpcpType.LOCAL, + LayerType.UNICAST: self._cli.IpcpType.UNICAST, + LayerType.BROADCAST: self._cli.IpcpType.BROADCAST, + LayerType.ETH_LLC: self._cli.IpcpType.ETH_LLC, + LayerType.ETH_DIX: self._cli.IpcpType.ETH_DIX, + LayerType.UDP4: self._cli.IpcpType.UDP4, + LayerType.UDP6: self._cli.IpcpType.UDP6, } return type_map[layer_type] @@ -253,9 +277,8 @@ class IrmPython(IrmBackend): def bootstrap_ipcp(self, node, name, layer_type, layer_name, policies=None, eth_dev=None, ip_addr=None, autobind=True): - pid = self._cli.pid_of(name) ipcp_type = self._get_ipcp_type(layer_type) - irm = self._irm + cli = self._cli # Build config based on type if layer_type == LayerType.UNICAST: @@ -269,28 +292,28 @@ class IrmPython(IrmBackend): for comp, pol in policies.items(): if comp == 'rmt.pff': pol_map = { - 'lfa': irm.LinkStatePolicy.LFA, - 'ecmp': irm.LinkStatePolicy.ECMP, - 'simple': irm.LinkStatePolicy.SIMPLE, + 'lfa': cli.LinkStatePolicy.LFA, + 'ecmp': cli.LinkStatePolicy.ECMP, + 'simple': cli.LinkStatePolicy.SIMPLE, } if pol in pol_map: ls_kwargs['pol'] = pol_map[pol] if ls_kwargs: - routing_kwargs['ls'] = irm.LinkStateConfig(**ls_kwargs) + routing_kwargs['ls'] = cli.LinkStateConfig(**ls_kwargs) if routing_kwargs: - dt_kwargs['routing'] = irm.RoutingConfig(**routing_kwargs) + dt_kwargs['routing'] = cli.RoutingConfig(**routing_kwargs) if dt_kwargs: - uc_kwargs['dt'] = irm.DtConfig(**dt_kwargs) + uc_kwargs['dt'] = cli.DtConfig(**dt_kwargs) - conf = irm.IpcpConfig( + conf = cli.IpcpConfig( ipcp_type=ipcp_type, layer_name=layer_name, - unicast=irm.UnicastConfig(**uc_kwargs)) + unicast=cli.UnicastConfig(**uc_kwargs)) elif layer_type in (LayerType.ETH_DIX, LayerType.ETH_LLC): - eth_conf = irm.EthConfig(dev=eth_dev or "") - conf = irm.IpcpConfig( + eth_conf = cli.EthConfig(dev=eth_dev or "") + conf = cli.IpcpConfig( ipcp_type=ipcp_type, layer_name=layer_name, eth=eth_conf) @@ -299,37 +322,35 @@ class IrmPython(IrmBackend): udp4_kwargs = {} if ip_addr: udp4_kwargs['ip_addr'] = ip_addr - conf = irm.IpcpConfig( + conf = cli.IpcpConfig( ipcp_type=ipcp_type, layer_name=layer_name, - udp4=irm.Udp4Config(**udp4_kwargs)) + udp4=cli.Udp4Config(**udp4_kwargs)) elif layer_type == LayerType.UDP6: udp6_kwargs = {} if ip_addr: udp6_kwargs['ip_addr'] = ip_addr - conf = irm.IpcpConfig( + conf = cli.IpcpConfig( ipcp_type=ipcp_type, layer_name=layer_name, - udp6=irm.Udp6Config(**udp6_kwargs)) + udp6=cli.Udp6Config(**udp6_kwargs)) else: - conf = irm.IpcpConfig( + conf = cli.IpcpConfig( ipcp_type=ipcp_type, layer_name=layer_name) - self._cli.bootstrap_ipcp(pid, conf, autobind=autobind) + self._cli.bootstrap_ipcp(name, conf, autobind=autobind) logger.debug("Bootstrapped IPCP %s in layer %s", name, layer_name) def enroll_ipcp(self, node, name, dst_name, autobind=True): - pid = self._cli.pid_of(name) - self._cli.enroll_ipcp(pid, dst_name, autobind=autobind) + self._cli.enroll_ipcp(name, dst_name, autobind=autobind) logger.debug("Enrolled IPCP %s via %s", name, dst_name) def connect_ipcp(self, node, name, dst_name): - pid = self._cli.pid_of(name) - self._cli.connect_ipcp(pid, dst_name) + self._cli.connect_ipcp(name, dst_name) logger.debug("Connected IPCP %s to %s", name, dst_name) def reg_name(self, node, name, ipcp_names): diff --git a/rumba/prototypes/ouroboros.py b/rumba/prototypes/ouroboros.py index ce05181..1c2e007 100644 --- a/rumba/prototypes/ouroboros.py +++ b/rumba/prototypes/ouroboros.py @@ -34,7 +34,6 @@ import rumba.multiprocess as m_processing import rumba.log as log import rumba.testbeds.local as local import rumba.testbeds.localnet as localnet -import rumba.testbeds.dockertb as docker import rumba.storyboard as sb from rumba.elements.topology import LayerType from rumba.irm_backend import IrmPython, IrmCLI @@ -186,8 +185,12 @@ class Experiment(mod.Experiment): self.exec_local_cmd(cmd) def setup_ouroboros(self): - if isinstance(self.testbed, docker.Testbed): - return + try: + import rumba.testbeds.dockertb as dockertb + if isinstance(self.testbed, dockertb.Testbed): + return + except ImportError: + pass if self._is_local: subprocess.check_call('sudo -v'.split()) diff --git a/setup.py b/setup.py deleted file mode 100755 index 68a7253..0000000 --- a/setup.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python - -import re -import setuptools - -with open('rumba/_version.py') as fp: - _version_src = fp.read() -_match = re.search(r'__version_info__\s*=\s*\((\d+),\s*(\d+),\s*(\d+)\)', - _version_src) -version = '%s.%s.%s' % _match.groups() - -with open('README.md') as fp: - long_description = fp.read() - -setuptools.setup( - name='Rumba', - version=version, - url='https://codeberg.org/o7s/rumba', - keywords='ouroboros measurement testbed', - author='Sander Vrijders, Dimitri Staessens', - author_email='sander@ouroboros.rocks, dimitri@ouroboros.rocks', - license='LGPL', - description='Rumba measurement framework for Ouroboros', - long_description=long_description, - long_description_content_type='text/markdown', - classifiers=[ - 'Development Status :: 4 - Beta', - 'License :: OSI Approved ' - ':: GNU Lesser General Public License v2 or later (LGPLv2+)', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: 3.13', - 'Programming Language :: Python :: 3.14', - 'Topic :: System :: Networking', - ], - packages=setuptools.find_packages(exclude=['examples', 'tools', 'doc']), - python_requires='>=3.8', - install_requires=[ - 'paramiko>=2.0,<4', - 'docker>=5.0,<8', - ], - extras_require={ - 'NumpyAcceleration': ['numpy'], - 'graphs': ['pydot'], - 'visualizer': ['igraph', 'plotly'], - 'pyouroboros': ['PyOuroboros'], - }, - scripts=['tools/rumba-access'], -) |
