From 63b6bb31bb9ce019b21b98869e72df2a8314b7fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Thu, 8 Aug 2024 13:45:56 +0200 Subject: [PATCH 01/20] [gcp][fix] Import cleanup --- plugins/gcp/fix_plugin_gcp/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/gcp/fix_plugin_gcp/__init__.py b/plugins/gcp/fix_plugin_gcp/__init__.py index 8b6a3b95e4..88ef1b6558 100644 --- a/plugins/gcp/fix_plugin_gcp/__init__.py +++ b/plugins/gcp/fix_plugin_gcp/__init__.py @@ -3,8 +3,7 @@ from typing import Optional, Dict, Any import fixlib.proc -from fixlib.args import ArgumentParser -from fixlib.args import Namespace +from fixlib.args import ArgumentParser, Namespace from fixlib.baseplugin import BaseCollectorPlugin from fixlib.baseresources import Cloud from fixlib.config import Config, RunningConfig From 169b653ec6a41670e9486b31504445a6eb9fb5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Thu, 8 Aug 2024 16:53:09 +0200 Subject: [PATCH 02/20] [fixlib][feat] Add long_name to BaseZone --- fixlib/fixlib/baseresources.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fixlib/fixlib/baseresources.py b/fixlib/fixlib/baseresources.py index a1e1d7b4f0..488a1b6773 100644 --- a/fixlib/fixlib/baseresources.py +++ b/fixlib/fixlib/baseresources.py @@ -893,6 +893,8 @@ class BaseZone(PhantomBaseResource): kind_description: ClassVar[str] = "A zone." metadata: ClassVar[Dict[str, Any]] = {"icon": "zone", "group": "control"} + long_name: Optional[str] = None + def zone(self, graph: Optional[Any] = None) -> BaseZone: return self From 08691b6aff866443b5c6acaac864c5a2bb8302f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Thu, 8 Aug 2024 16:58:29 +0200 Subject: [PATCH 03/20] [hetzner][feat] Initial Hetzner Cloud commit --- plugins/hetzner/MANIFEST.in | 1 + plugins/hetzner/README.md | 5 + .../hetzner/fix_plugin_hetzner/__init__.py | 64 +++++++++ plugins/hetzner/fix_plugin_hetzner/client.py | 5 + .../hetzner/fix_plugin_hetzner/collector.py | 130 ++++++++++++++++++ plugins/hetzner/fix_plugin_hetzner/config.py | 9 ++ .../hetzner/fix_plugin_hetzner/resources.py | 95 +++++++++++++ plugins/hetzner/pyproject.toml | 45 ++++++ plugins/hetzner/setup.cfg | 7 + plugins/hetzner/test/test_args.py | 13 ++ plugins/hetzner/test/test_config.py | 11 ++ plugins/hetzner/tox.ini | 29 ++++ 12 files changed, 414 insertions(+) create mode 100644 plugins/hetzner/MANIFEST.in create mode 100644 plugins/hetzner/README.md create mode 100644 plugins/hetzner/fix_plugin_hetzner/__init__.py create mode 100644 plugins/hetzner/fix_plugin_hetzner/client.py create mode 100644 plugins/hetzner/fix_plugin_hetzner/collector.py create mode 100644 plugins/hetzner/fix_plugin_hetzner/config.py create mode 100644 plugins/hetzner/fix_plugin_hetzner/resources.py create mode 100644 plugins/hetzner/pyproject.toml create mode 100644 plugins/hetzner/setup.cfg create mode 100644 plugins/hetzner/test/test_args.py create mode 100644 plugins/hetzner/test/test_config.py create mode 100644 plugins/hetzner/tox.ini diff --git a/plugins/hetzner/MANIFEST.in b/plugins/hetzner/MANIFEST.in new file mode 100644 index 0000000000..bb3ec5f0d4 --- /dev/null +++ b/plugins/hetzner/MANIFEST.in @@ -0,0 +1 @@ +include README.md diff --git a/plugins/hetzner/README.md b/plugins/hetzner/README.md new file mode 100644 index 0000000000..393dd4c86f --- /dev/null +++ b/plugins/hetzner/README.md @@ -0,0 +1,5 @@ +# fix-plugin-hetzner +Hetzner Collector Plugin for Fix + +## License +See [LICENSE](../../LICENSE) for details. diff --git a/plugins/hetzner/fix_plugin_hetzner/__init__.py b/plugins/hetzner/fix_plugin_hetzner/__init__.py new file mode 100644 index 0000000000..31b80c5a36 --- /dev/null +++ b/plugins/hetzner/fix_plugin_hetzner/__init__.py @@ -0,0 +1,64 @@ +import fixlib.logger +from fixlib.baseplugin import BaseCollectorPlugin +from fixlib.args import ArgumentParser +from fixlib.config import Config +from fixlib.core.actions import CoreFeedback +from fixlib.graph import Graph, MaxNodesExceeded +from fixlib.baseresources import Cloud +from fixlib.logger import log +from typing import Any, Optional +from .config import HetznerConfig +from .collector import HcloudCollector +from .resources import HcloudProject + +log = fixlib.logger.getLogger("fix." + __name__) + + +class HetznerCollectorPlugin(BaseCollectorPlugin): + cloud = "hetzner" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.core_feedback: Optional[CoreFeedback] = None + + def collect(self) -> None: + assert self.core_feedback, "core_feedback is not set" + if len(Config.hetzner.hcloud_tokens) != len(Config.hetzner.hcloud_project_names): + log.error("The number of tokens and project names must be the same!") + return + self.collect_hcloud() + + def collect_hcloud(self) -> None: + log.debug("plugin: collecting Hetzner Cloud resources") + feedback = self.core_feedback.with_context("hetzner") + cloud = Cloud(id=self.cloud, name="Hetzner") + + for i, api_token in enumerate(Config.hetzner.hcloud_tokens): + project = HcloudProject(id=Config.hetzner.hcloud_project_names[i]) + self.core_feedback.progress_done(project.id, 0, 1) + collector = HcloudCollector(cloud, project, api_token, feedback, self.max_resources_per_account) + try: + collector.collect() + self.send_account_graph(collector.graph) + except MaxNodesExceeded: + log.error(f"Max nodes exceeded, stopping collection in {project.kdname}") + continue + except Exception as e: + log.error(f"Error collecting resources in {project.kdname}: {e}") + continue + finally: + self.core_feedback.progress_done(project.id, 1, 1) + + @staticmethod + def add_args(arg_parser: ArgumentParser) -> None: + pass + + @staticmethod + def add_config(config: Config) -> None: + """Add any plugin config to the global config store. + + Method called by the PluginLoader upon plugin initialization. + Can be used to introduce plugin config arguments to the global config store. + """ + config.add_config(HetznerConfig) + pass diff --git a/plugins/hetzner/fix_plugin_hetzner/client.py b/plugins/hetzner/fix_plugin_hetzner/client.py new file mode 100644 index 0000000000..d5daf25853 --- /dev/null +++ b/plugins/hetzner/fix_plugin_hetzner/client.py @@ -0,0 +1,5 @@ +from hcloud import Client + + +def get_client(api_token: str) -> Client: + return Client(token=api_token) diff --git a/plugins/hetzner/fix_plugin_hetzner/collector.py b/plugins/hetzner/fix_plugin_hetzner/collector.py new file mode 100644 index 0000000000..14edd90bcd --- /dev/null +++ b/plugins/hetzner/fix_plugin_hetzner/collector.py @@ -0,0 +1,130 @@ +from typing import Optional +from fixlib.logger import log +from fixlib.core.actions import CoreFeedback +from fixlib.baseresources import Cloud, VolumeStatus +from fixlib.graph import Graph +from .resources import HcloudProject, HcloudLocation, HcloudDatacenter, HcloudServer, HcloudVolume +from .client import get_client + + +class HcloudCollector: + def __init__( + self, + cloud: Cloud, + project: HcloudProject, + api_token: str, + core_feedback: CoreFeedback, + max_resources_per_account: Optional[int] = None, + ) -> None: + self.cloud = cloud + self.core_feedback = core_feedback + self.api_token = api_token + self.project = project + self.api_token = api_token + self.graph = Graph(root=self.project, max_nodes=max_resources_per_account) + + def collect(self): + log.info(f"Collecting resources in {self.project.kdname}") + self.add_locations() + self.add_datacenters() + self.add_volumes() + self.add_servers() + + def add_locations(self): + client = get_client(self.api_token) + for location in client.locations.get_all(): + l = HcloudLocation( + id=location.name, + name=location.name, + long_name=location.description, + latitude=location.latitude, + longitude=location.longitude, + cloud=self.cloud, + account=self.project, + ) + self.graph.add_resource(self.project, l) + + def add_datacenters(self): + client = get_client(self.api_token) + for datacenter in client.datacenters.get_all(): + l = self.graph.search_first_all({"kind": "hcloud_location", "id": datacenter.location.name}) + if not l: + log.error(f"Location {datacenter.location.name} not found for datacenter {datacenter.name}") + continue + d = HcloudDatacenter( + id=datacenter.name, + name=datacenter.name, + long_name=datacenter.description, + cloud=self.cloud, + account=self.project, + region=l, + ) + self.graph.add_resource(l, d) + + def add_volumes(self): + client = get_client(self.api_token) + for volume in client.volumes.get_all(): + l = self.graph.search_first_all({"kind": "hcloud_location", "id": volume.location.name}) + if not l: + log.error(f"Location {volume.location.name} not found for volume {volume.name}") + continue + + volume_status = VolumeStatus.UNKNOWN + if volume.status == "available": + if volume.server is None: + volume_status = VolumeStatus.AVAILABLE + else: + volume_status = VolumeStatus.IN_USE + elif volume.status == "creating": + volume_status = VolumeStatus.BUSY + + v = HcloudVolume( + id=volume.name, + name=volume.name, + tags=volume.labels, + ctime=volume.created, + volume_size=volume.size, + volume_status=volume_status, + linux_device=volume.linux_device, + protection=volume.protection, + format=volume.format, + cloud=self.cloud, + account=self.project, + region=l, + ) + self.graph.add_resource(l, v) + + def add_servers(self): + client = get_client(self.api_token) + for server in client.servers.get_all(): + d = self.graph.search_first_all({"kind": "hcloud_datacenter", "id": server.datacenter.name}) + if not d: + log.error(f"Datacenter {server.datacenter.name} not found for server {server.name}") + continue + l = d.region() + s = HcloudServer( + id=server.name, + name=server.name, + ctime=server.created, + tags=server.labels, + rescue_enabled=server.rescue_enabled, + locked=server.locked, + backup_window=server.backup_window, + outgoing_traffic=server.outgoing_traffic, + ingoing_traffic=server.ingoing_traffic, + included_traffic=server.included_traffic, + primary_disk_size=server.primary_disk_size, + protection=server.protection, + cloud=self.cloud, + account=self.project, + region=l, + zone=d, + ) + self.graph.add_resource(l, s) + self.graph.add_edge(d, s) + for volume in server.volumes: + v = self.graph.search_first_all({"kind": "hcloud_volume", "id": volume.name}) + if not v: + log.error(f"Volume {volume.name} not found for server {server.name}") + continue + self.graph.add_edge(s, v) diff --git a/plugins/hetzner/fix_plugin_hetzner/config.py b/plugins/hetzner/fix_plugin_hetzner/config.py new file mode 100644 index 0000000000..bd3bcd6ae8 --- /dev/null +++ b/plugins/hetzner/fix_plugin_hetzner/config.py @@ -0,0 +1,9 @@ +from attrs import define, field +from typing import ClassVar, List + + +@define +class HetznerConfig: + kind: ClassVar[str] = "hetzner" + hcloud_project_names: List[str] = field(factory=list, metadata={"description": "Hetzner Cloud project names"}) + hcloud_tokens: List[str] = field(factory=list, metadata={"description": "Hetzner Cloud project API tokens"}) diff --git a/plugins/hetzner/fix_plugin_hetzner/resources.py b/plugins/hetzner/fix_plugin_hetzner/resources.py new file mode 100644 index 0000000000..ab9041b96c --- /dev/null +++ b/plugins/hetzner/fix_plugin_hetzner/resources.py @@ -0,0 +1,95 @@ +from attrs import define, field +from typing import ClassVar, List, Optional, Dict +from datetime import datetime +from fixlib.graph import Graph +from fixlib.logger import log +from fixlib.baseresources import ( + BaseAccount, + BaseRegion, + BaseZone, + BaseInstance, + BaseNetwork, + BaseResource, + BaseVolume, + InstanceStatus, + VolumeStatus, +) + + +@define(eq=False, slots=False) +class HcloudResource(BaseResource): + kind: ClassVar[str] = "hcloud_resource" + kind_display: ClassVar[str] = "Hetzner Cloud Resource" + kind_description: ClassVar[str] = "A Hetzner Cloud Resource represents a single resource in the Hetzner Cloud" + + def delete(self, graph: Graph) -> bool: + return NotImplemented + + def update_tag(self, key, value) -> bool: + return NotImplemented + + def delete_tag(self, key) -> bool: + return NotImplemented + + +@define(eq=False, slots=False) +class HcloudProject(BaseAccount, HcloudResource): + kind: ClassVar[str] = "hcloud_project" + + +@define(eq=False, slots=False) +class HcloudLocation(BaseRegion, HcloudResource): + kind: ClassVar[str] = "hcloud_location" + + +@define(eq=False, slots=False) +class HcloudDatacenter(BaseZone, HcloudResource): + kind: ClassVar[str] = "hcloud_datacenter" + + +@define(eq=False, slots=False) +class HcloudPublicNet(HcloudResource): + kind: ClassVar[str] = "hcloud_public_net" + + +@define(eq=False, slots=False) +class HcloudServerType(HcloudResource): + kind: ClassVar[str] = "hcloud_server_type" + + +@define(eq=False, slots=False) +class HcloudImage(HcloudResource): + kind: ClassVar[str] = "hcloud_image" + + +@define(eq=False, slots=False) +class HcloudIso(HcloudResource): + kind: ClassVar[str] = "hcloud_iso" + + +@define(eq=False, slots=False) +class HcloudVolume(BaseVolume, HcloudResource): + kind: ClassVar[str] = "hcloud_volume" + + linux_device: Optional[str] = None + protection: Optional[dict[str, bool]] = None + format: Optional[str] = None + + +@define(eq=False, slots=False) +class HcloudPrivateNet(BaseNetwork, HcloudResource): + kind: ClassVar[str] = "hcloud_private_net" + + +@define(eq=False, slots=False) +class HcloudServer(BaseInstance, HcloudResource): + kind: ClassVar[str] = "hcloud_server" + + rescue_enabled: Optional[bool] = None + locked: Optional[bool] = None + backup_window: Optional[str] = None + outgoing_traffic: Optional[int] = None + ingoing_traffic: Optional[int] = None + included_traffic: Optional[int] = None + primary_disk_size: Optional[int] = None + protection: Optional[dict[str, bool]] = None diff --git a/plugins/hetzner/pyproject.toml b/plugins/hetzner/pyproject.toml new file mode 100644 index 0000000000..35ffae2a94 --- /dev/null +++ b/plugins/hetzner/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "fixinventory-plugin-hetzner" +description = "Fix Hetzner Collector Plugin" +version = "4.1.0" +authors = [{name="Some Engineering Inc."}] +license = { text="AGPLv3" } +requires-python = ">=3.11" +classifiers = [ + # Current project status + "Development Status :: 4 - Beta", + # Audience + "Intended Audience :: System Administrators", + "Intended Audience :: Information Technology", + # License information + "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", + # Supported python versions + "Programming Language :: Python :: 3.11", + # Supported OS's + "Operating System :: POSIX :: Linux", + "Operating System :: Unix", + # Extra metadata + "Environment :: Console", + "Natural Language :: English", + "Topic :: Security", + "Topic :: Utilities", +] +readme = {file="README.md", content-type="text/markdown"} + +dependencies = [ + "fixinventorylib==4.1.0", + "hcloud==2.2.0", +] + +[project.entry-points."fix.plugins"] +hetzner_collector = "fix_plugin_hetzner:HetznerCollectorPlugin" + +[project.urls] +Documentation = "https://inventory.fix.security" +Source = "https://github.com/someengineering/fix/tree/main/plugins/hetzner" + +[build-system] +requires = ["setuptools>=67.8.0", "wheel>=0.40.0", "build>=0.10.0"] +build-backend = "setuptools.build_meta" + + diff --git a/plugins/hetzner/setup.cfg b/plugins/hetzner/setup.cfg new file mode 100644 index 0000000000..7ca6537935 --- /dev/null +++ b/plugins/hetzner/setup.cfg @@ -0,0 +1,7 @@ +[options] +packages = find: +include_package_data = True +zip_safe = False + +[aliases] +test=pytest diff --git a/plugins/hetzner/test/test_args.py b/plugins/hetzner/test/test_args.py new file mode 100644 index 0000000000..c7add9b5ab --- /dev/null +++ b/plugins/hetzner/test/test_args.py @@ -0,0 +1,13 @@ +from fixlib.args import get_arg_parser +from fix_plugin_hetzner import HetznerCollectorPlugin + +# from fixlib.args import ArgumentParser + + +def test_args(): + arg_parser = get_arg_parser() + HetznerCollectorPlugin.add_args(arg_parser) + arg_parser.parse_args() + + +# assert ArgumentParser.args.example_arg is None diff --git a/plugins/hetzner/test/test_config.py b/plugins/hetzner/test/test_config.py new file mode 100644 index 0000000000..a93af18041 --- /dev/null +++ b/plugins/hetzner/test/test_config.py @@ -0,0 +1,11 @@ +from fixlib.config import Config +from fix_plugin_example_collector import ExampleCollectorPlugin + + +def test_config(): + config = Config("dummy", "dummy") + ExampleCollectorPlugin.add_config(config) + Config.init_default_config() + + +# assert Config.example.region is None diff --git a/plugins/hetzner/tox.ini b/plugins/hetzner/tox.ini new file mode 100644 index 0000000000..c550b7abb6 --- /dev/null +++ b/plugins/hetzner/tox.ini @@ -0,0 +1,29 @@ +[tox] +env_list = syntax, tests, black + +[flake8] +max-line-length=120 +exclude = .git,.tox,__pycache__,.idea,.pytest_cache +ignore=F403, F405, E722, N806, N813, E266, W503, E203 + +[pytest] +addopts= --cov=fix_plugin_hetzner -rs -vv --cov-report html +testpaths= test + +[testenv] +usedevelop = true +deps = + --editable=file:///{toxinidir}/../../fixlib + -r../../requirements-all.txt +# until this is fixed: https://github.com/pypa/setuptools/issues/3518 +setenv = + SETUPTOOLS_ENABLE_FEATURES = legacy-editable + +[testenv:syntax] +commands = flake8 --verbose + +[testenv:tests] +commands= pytest + +[testenv:black] +commands = black --line-length 120 --check --diff --target-version py39 . From 0b9c506a9e195eae8a0ced6cf71f225a6ac8bdbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Thu, 8 Aug 2024 17:00:47 +0200 Subject: [PATCH 04/20] Update tests --- plugins/hetzner/test/test_args.py | 5 ----- plugins/hetzner/test/test_config.py | 8 +++----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/plugins/hetzner/test/test_args.py b/plugins/hetzner/test/test_args.py index c7add9b5ab..d69db7620b 100644 --- a/plugins/hetzner/test/test_args.py +++ b/plugins/hetzner/test/test_args.py @@ -1,13 +1,8 @@ from fixlib.args import get_arg_parser from fix_plugin_hetzner import HetznerCollectorPlugin -# from fixlib.args import ArgumentParser - def test_args(): arg_parser = get_arg_parser() HetznerCollectorPlugin.add_args(arg_parser) arg_parser.parse_args() - - -# assert ArgumentParser.args.example_arg is None diff --git a/plugins/hetzner/test/test_config.py b/plugins/hetzner/test/test_config.py index a93af18041..59eb3ec6c5 100644 --- a/plugins/hetzner/test/test_config.py +++ b/plugins/hetzner/test/test_config.py @@ -1,11 +1,9 @@ from fixlib.config import Config -from fix_plugin_example_collector import ExampleCollectorPlugin +from fix_plugin_hetzner import HetznerCollectorPlugin def test_config(): config = Config("dummy", "dummy") - ExampleCollectorPlugin.add_config(config) + HetznerCollectorPlugin.add_config(config) Config.init_default_config() - - -# assert Config.example.region is None + assert Config.hetzner.hcloud_tokens == [] From ee8d29df294ba8f7d9d34c164bb7aa13bd5ef2f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Thu, 8 Aug 2024 17:12:20 +0200 Subject: [PATCH 05/20] Add CI workflow --- .github/workflows/check_pr_plugin_hetzner.yml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/check_pr_plugin_hetzner.yml diff --git a/.github/workflows/check_pr_plugin_hetzner.yml b/.github/workflows/check_pr_plugin_hetzner.yml new file mode 100644 index 0000000000..8876b536c6 --- /dev/null +++ b/.github/workflows/check_pr_plugin_hetzner.yml @@ -0,0 +1,71 @@ +# Note: this workflow is automatically generated via the `create_pr` script in the same folder. +# Please do not change the file, but the script! + +name: Check PR (Plugin hetzner) +on: + push: + tags: + - "*.*.*" + branches: + - main + pull_request: + paths: + - 'fixlib/**' + - 'plugins/hetzner/**' + - '.github/**' + - 'requirements-all.txt' + +jobs: + hetzner: + name: "hetzner" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + architecture: 'x64' + + - name: Restore dependency cache + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{runner.os}}-pip-${{hashFiles('./plugins/hetzner/pyproject.toml')}} + restore-keys: | + ${{runner.os}}-pip- + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade --editable fixlib/ + pip install tox wheel flake8 build + + - name: Run tests + working-directory: ./plugins/hetzner + run: tox + + - name: Archive code coverage results + uses: actions/upload-artifact@v2 + with: + name: plugin-hetzner-code-coverage-report + path: ./plugins/hetzner/htmlcov/ + + - name: Build a binary wheel and a source tarball + working-directory: ./plugins/hetzner + run: >- + python -m + build + --sdist + --wheel + --outdir dist/ + + - name: Publish distribution to PyPI + if: github.ref_type == 'tag' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_FIXINVENTORY_PLUGIN_HETZNER }} + packages_dir: ./plugins/hetzner/dist/ From a65a4e8d04df6b2b4fa31f69a31372811f8a3ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Thu, 8 Aug 2024 17:14:19 +0200 Subject: [PATCH 06/20] Update unused imports --- plugins/hetzner/README.md | 2 ++ plugins/hetzner/fix_plugin_hetzner/__init__.py | 3 +-- plugins/hetzner/fix_plugin_hetzner/resources.py | 6 +----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/hetzner/README.md b/plugins/hetzner/README.md index 393dd4c86f..422a0849d2 100644 --- a/plugins/hetzner/README.md +++ b/plugins/hetzner/README.md @@ -1,5 +1,7 @@ # fix-plugin-hetzner + Hetzner Collector Plugin for Fix ## License + See [LICENSE](../../LICENSE) for details. diff --git a/plugins/hetzner/fix_plugin_hetzner/__init__.py b/plugins/hetzner/fix_plugin_hetzner/__init__.py index 31b80c5a36..8ed3cf1ab6 100644 --- a/plugins/hetzner/fix_plugin_hetzner/__init__.py +++ b/plugins/hetzner/fix_plugin_hetzner/__init__.py @@ -3,7 +3,7 @@ from fixlib.args import ArgumentParser from fixlib.config import Config from fixlib.core.actions import CoreFeedback -from fixlib.graph import Graph, MaxNodesExceeded +from fixlib.graph import MaxNodesExceeded from fixlib.baseresources import Cloud from fixlib.logger import log from typing import Any, Optional @@ -61,4 +61,3 @@ def add_config(config: Config) -> None: Can be used to introduce plugin config arguments to the global config store. """ config.add_config(HetznerConfig) - pass diff --git a/plugins/hetzner/fix_plugin_hetzner/resources.py b/plugins/hetzner/fix_plugin_hetzner/resources.py index ab9041b96c..68cde6c2f5 100644 --- a/plugins/hetzner/fix_plugin_hetzner/resources.py +++ b/plugins/hetzner/fix_plugin_hetzner/resources.py @@ -1,8 +1,6 @@ from attrs import define, field -from typing import ClassVar, List, Optional, Dict -from datetime import datetime +from typing import ClassVar, Optional from fixlib.graph import Graph -from fixlib.logger import log from fixlib.baseresources import ( BaseAccount, BaseRegion, @@ -11,8 +9,6 @@ BaseNetwork, BaseResource, BaseVolume, - InstanceStatus, - VolumeStatus, ) From ee60d66247662d5b6a5249a444c96f1528017f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Thu, 8 Aug 2024 17:43:51 +0200 Subject: [PATCH 07/20] Update strings --- plugins/hetzner/fix_plugin_hetzner/config.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/plugins/hetzner/fix_plugin_hetzner/config.py b/plugins/hetzner/fix_plugin_hetzner/config.py index bd3bcd6ae8..4f81d1cd1a 100644 --- a/plugins/hetzner/fix_plugin_hetzner/config.py +++ b/plugins/hetzner/fix_plugin_hetzner/config.py @@ -5,5 +5,14 @@ @define class HetznerConfig: kind: ClassVar[str] = "hetzner" - hcloud_project_names: List[str] = field(factory=list, metadata={"description": "Hetzner Cloud project names"}) + hcloud_project_names: List[str] = field( + factory=list, + metadata={ + "description": ( + "Hetzner Cloud project names - Hetzner has no API to introspect a token, so you need to manually maintain" + " the project name associated with an API token. Provide names in the same order as the corresponding API" + " tokens." + ) + }, + ) hcloud_tokens: List[str] = field(factory=list, metadata={"description": "Hetzner Cloud project API tokens"}) From 50bec72b9dd2fcfb951db0a4cc39f7521965c501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 16 Aug 2024 20:11:09 +0200 Subject: [PATCH 08/20] More resources --- fixlib/fixlib/baseresources.py | 9 + .../hetzner/fix_plugin_hetzner/collector.py | 231 +++++++++++++++++- .../hetzner/fix_plugin_hetzner/resources.py | 155 +++++++++++- 3 files changed, 382 insertions(+), 13 deletions(-) diff --git a/fixlib/fixlib/baseresources.py b/fixlib/fixlib/baseresources.py index 488a1b6773..a5e158150b 100644 --- a/fixlib/fixlib/baseresources.py +++ b/fixlib/fixlib/baseresources.py @@ -1195,6 +1195,15 @@ class BaseRoutingTable(BaseResource): _categories: ClassVar[List[Category]] = [Category.networking] +@define(eq=False, slots=False) +class BaseRoute(BaseResource): + kind: ClassVar[str] = "route" + kind_display: ClassVar[str] = "Network Route" + kind_description: ClassVar[str] = "A network route." + metadata: ClassVar[Dict[str, Any]] = {"icon": "route", "group": "networking"} + _categories: ClassVar[List[Category]] = [Category.networking] + + @define(eq=False, slots=False) class BaseNetworkAcl(BaseResource): kind: ClassVar[str] = "network_acl" diff --git a/plugins/hetzner/fix_plugin_hetzner/collector.py b/plugins/hetzner/fix_plugin_hetzner/collector.py index 14edd90bcd..508e452c4a 100644 --- a/plugins/hetzner/fix_plugin_hetzner/collector.py +++ b/plugins/hetzner/fix_plugin_hetzner/collector.py @@ -3,7 +3,27 @@ from fixlib.core.actions import CoreFeedback from fixlib.baseresources import Cloud, VolumeStatus from fixlib.graph import Graph -from .resources import HcloudProject, HcloudLocation, HcloudDatacenter, HcloudServer, HcloudVolume +from .resources import ( + HcloudProject, + HcloudLocation, + HcloudDatacenter, + HcloudServer, + HcloudVolume, + HcloudNetwork, + HcloudSubnet, + HcloudRoute, + HcloudIso, + HcloudImage, + HcloudDeprecationInfo, + HcloudServerType, + HcloudFloatingIP, + HcloudPrimaryIP, + HcloudPrivateNetwork, + HcloudPublicNetwork, + HcloudIPv4Address, + HcloudIPv6Network, + HcloudPrimaryIP, +) from .client import get_client @@ -27,13 +47,20 @@ def collect(self): log.info(f"Collecting resources in {self.project.kdname}") self.add_locations() self.add_datacenters() + self.add_server_types() + self.add_isos() + self.add_primary_ips() self.add_volumes() self.add_servers() + self.add_networks() + self.add_floating_ips() def add_locations(self): + log.info(f"Collecting locations in {self.project.kdname}") client = get_client(self.api_token) for location in client.locations.get_all(): l = HcloudLocation( + hcloud_id=location.id, id=location.name, name=location.name, long_name=location.description, @@ -45,6 +72,7 @@ def add_locations(self): self.graph.add_resource(self.project, l) def add_datacenters(self): + log.info(f"Collecting datacenters in {self.project.kdname}") client = get_client(self.api_token) for datacenter in client.datacenters.get_all(): l = self.graph.search_first_all({"kind": "hcloud_location", "id": datacenter.location.name}) @@ -52,6 +80,7 @@ def add_datacenters(self): log.error(f"Location {datacenter.location.name} not found for datacenter {datacenter.name}") continue d = HcloudDatacenter( + hcloud_id=datacenter.id, id=datacenter.name, name=datacenter.name, long_name=datacenter.description, @@ -61,7 +90,42 @@ def add_datacenters(self): ) self.graph.add_resource(l, d) + def add_networks(self): + log.info(f"Collecting networks in {self.project.kdname}") + client = get_client(self.api_token) + for network in client.networks.get_all(): + n = HcloudNetwork( + hcloud_id=network.id, + id=network.name, + name=network.name, + tags=network.labels, + cloud=self.cloud, + account=self.project, + ip_range=network.ip_range, + network_subnets=[ + HcloudSubnet( + type=s.type, + ip_range=s.ip_range, + network_zone=s.network_zone, + gateway=s.gateway, + vswitch_id=s.vswitch_id, + ) + for s in network.subnets + ], + network_routes=[HcloudRoute(destination=r.destination, gateway=r.gateway) for r in network.routes], + expose_routes_to_vswitch=network.expose_routes_to_vswitch, + protection=network.protection, + ) + self.graph.add_resource(self.project, n) + for server in network.servers: + s = self.graph.search_first_all({"kind": "hcloud_server", "id": server.name}) + if not s: + log.error(f"Server {server.name} not found for network {network.name}") + continue + self.graph.add_edge(n, s) + def add_volumes(self): + log.info(f"Collecting volumes in {self.project.kdname}") client = get_client(self.api_token) for volume in client.volumes.get_all(): l = self.graph.search_first_all({"kind": "hcloud_location", "id": volume.location.name}) @@ -79,6 +143,7 @@ def add_volumes(self): volume_status = VolumeStatus.BUSY v = HcloudVolume( + hcloud_id=volume.id, id=volume.name, name=volume.name, tags=volume.labels, @@ -95,6 +160,7 @@ def add_volumes(self): self.graph.add_resource(l, v) def add_servers(self): + log.info(f"Collecting servers in {self.project.kdname}") client = get_client(self.api_token) for server in client.servers.get_all(): d = self.graph.search_first_all({"kind": "hcloud_datacenter", "id": server.datacenter.name}) @@ -102,11 +168,54 @@ def add_servers(self): log.error(f"Datacenter {server.datacenter.name} not found for server {server.name}") continue l = d.region() + + public_net = None + floating_ips = None + if server.public_net: + ipv4 = None + ipv6 = None + primary_ipv4 = None + primary_ipv6 = None + firewalls = None + if server.public_net.ipv4: + ipv4 = HcloudIPv4Address( + ip_address=server.public_net.ipv4.ip, + blocked=server.public_net.ipv4.blocked, + dns_ptr=server.public_net.ipv4.dns_ptr, + ) + if server.public_net.ipv6: + ipv6 = HcloudIPv6Network( + ip_address=server.public_net.ipv6.ip, + blocked=server.public_net.ipv6.blocked, + dns_ptr=server.public_net.ipv6.dns_ptr, + network=server.public_net.ipv6.network, + network_mask=server.public_net.ipv6.network_mask, + ) + public_net = HcloudPublicNetwork( + ipv4=ipv4, + ipv6=ipv6, + ) + + private_net = None + if server.private_net: + for pnet in server.private_net: + pn = HcloudPrivateNetwork( + ip_address=pnet.ip, + alias_ips=pnet.alias_ips, + mac_address=pnet.mac_address, + ) + if not private_net: + private_net = [] + private_net.append(pn) + s = HcloudServer( + hcloud_id=server.id, id=server.name, name=server.name, ctime=server.created, tags=server.labels, + public_net=public_net, + private_net=private_net, rescue_enabled=server.rescue_enabled, locked=server.locked, backup_window=server.backup_window, @@ -128,3 +237,123 @@ def add_servers(self): log.error(f"Volume {volume.name} not found for server {server.name}") continue self.graph.add_edge(s, v) + + if server.public_net: + if server.public_net.primary_ipv4: + primary_ipv4 = self.graph.search_first_all( + {"kind": "hcloud_primary_ip", "id": server.public_net.primary_ipv4.ip} + ) + if primary_ipv4: + self.graph.add_edge(s, primary_ipv4) + if server.public_net.primary_ipv6: + primary_ipv6 = self.graph.search_first_all( + {"kind": "hcloud_primary_ip", "id": server.public_net.primary_ipv6.ip} + ) + if primary_ipv6: + self.graph.add_edge(s, primary_ipv6) + + def add_isos(self): + log.info(f"Collecting ISOs in {self.project.kdname}") + client = get_client(self.api_token) + for iso in client.isos.get_all(): + deprecation = None + if iso.deprecation: + deprecation = HcloudDeprecationInfo( + announced_at=iso.deprecation.announced, + unavailable_after=iso.deprecation.unavailable_after, + ) + i = HcloudIso( + hcloud_id=iso.id, + id=iso.name, + name=iso.name, + cloud=self.cloud, + account=self.project, + description=iso.description, + type=iso.type, + deprecated_at=iso.deprecated, + deprecation=deprecation, + ) + self.graph.add_resource(self.project, i) + + def add_server_types(self): + log.info(f"Collecting server types in {self.project.kdname}") + client = get_client(self.api_token) + for server_type in client.server_types.get_all(): + deprecation = None + if server_type.deprecation: + deprecation = HcloudDeprecationInfo( + announced_at=server_type.deprecation.announced, + unavailable_after=server_type.deprecation.unavailable_after, + ) + st = HcloudServerType( + hcloud_id=server_type.id, + id=server_type.name, + name=server_type.name, + cloud=self.cloud, + account=self.project, + description=server_type.description, + instance_cores=server_type.cores, + instance_memory=server_type.memory, + volume_size=server_type.disk, + prices=server_type.prices, + storage_type=server_type.storage_type, + cpu_type=server_type.cpu_type, + architecture=server_type.architecture, + deprecated=server_type.deprecated, + deprecation=deprecation, + ) + self.graph.add_resource(self.project, st) + + def add_floating_ips(self): + log.info(f"Collecting floating IPs in {self.project.kdname}") + client = get_client(self.api_token) + for floating_ip in client.floating_ips.get_all(): + l = self.graph.search_first_all({"kind": "hcloud_location", "id": floating_ip.home_location.name}) + fi = HcloudFloatingIP( + hcloud_id=floating_ip.id, + id=floating_ip.ip, + name=floating_ip.name, + tags=floating_ip.labels, + ctime=floating_ip.created, + cloud=self.cloud, + account=self.project, + region=l, + description=floating_ip.description, + ip_address=floating_ip.ip, + ip_address_family=floating_ip.type, + blocked=floating_ip.blocked, + dns_ptr=floating_ip.dns_ptr, + protection=floating_ip.protection, + ) + self.graph.add_resource(l, fi) + if floating_ip.server: + s = self.graph.search_first_all({"kind": "hcloud_server", "id": floating_ip.server.name}) + if s: + self.graph.add_edge(s, fi) + + def add_primary_ips(self): + log.info(f"Collecting primary IPs in {self.project.kdname}") + client = get_client(self.api_token) + for primary_ip in client.primary_ips.get_all(): + d = self.graph.search_first_all({"kind": "hcloud_datacenter", "id": primary_ip.datacenter.name}) + r = d.region() + p = HcloudPrimaryIP( + hcloud_id=primary_ip.id, + id=primary_ip.ip, + name=primary_ip.name, + tags=primary_ip.labels, + ctime=primary_ip.created, + cloud=self.cloud, + account=self.project, + region=r, + zone=d, + ip_address=primary_ip.ip, + ip_address_family=primary_ip.type, + blocked=primary_ip.blocked, + dns_ptr=primary_ip.dns_ptr, + assignee_id=primary_ip.assignee_id, + assigneer_type=primary_ip.assignee_type, + auto_delete=primary_ip.auto_delete, + protection=primary_ip.protection, + ) + self.graph.add_resource(r, p) diff --git a/plugins/hetzner/fix_plugin_hetzner/resources.py b/plugins/hetzner/fix_plugin_hetzner/resources.py index 68cde6c2f5..0afe21893d 100644 --- a/plugins/hetzner/fix_plugin_hetzner/resources.py +++ b/plugins/hetzner/fix_plugin_hetzner/resources.py @@ -1,5 +1,6 @@ -from attrs import define, field -from typing import ClassVar, Optional +from attrs import define +from typing import ClassVar, Optional, Union, Any +from datetime import datetime from fixlib.graph import Graph from fixlib.baseresources import ( BaseAccount, @@ -9,6 +10,8 @@ BaseNetwork, BaseResource, BaseVolume, + BaseInstanceType, + BaseIPAddress, ) @@ -18,6 +21,8 @@ class HcloudResource(BaseResource): kind_display: ClassVar[str] = "Hetzner Cloud Resource" kind_description: ClassVar[str] = "A Hetzner Cloud Resource represents a single resource in the Hetzner Cloud" + hcloud_id: Optional[int] = None + def delete(self, graph: Graph) -> bool: return NotImplemented @@ -44,23 +49,91 @@ class HcloudDatacenter(BaseZone, HcloudResource): @define(eq=False, slots=False) -class HcloudPublicNet(HcloudResource): - kind: ClassVar[str] = "hcloud_public_net" +class HcloudIPv4Address: + kind: ClassVar[str] = "hcloud_ipv4_address" + + ip_address: Optional[str] = None + blocked: Optional[bool] = None + dns_ptr: Optional[Union[str, list[dict[str, str]]]] = None @define(eq=False, slots=False) -class HcloudServerType(HcloudResource): - kind: ClassVar[str] = "hcloud_server_type" +class HcloudIPv6Network: + kind: ClassVar[str] = "hcloud_ipv6_network" + + ip_address: Optional[str] = None + blocked: Optional[bool] = None + dns_ptr: Optional[Union[str, list[dict[str, str]]]] = None + network: Optional[str] = None + network_mask: Optional[str] = None @define(eq=False, slots=False) -class HcloudImage(HcloudResource): - kind: ClassVar[str] = "hcloud_image" +class HcloudFloatingIP(BaseIPAddress, HcloudResource): + kind: ClassVar[str] = "hcloud_floating_ip" + + description: Optional[str] = None + dns_ptr: Optional[Union[str, list[dict[str, str]]]] = None + home_location: Optional[HcloudLocation] = None + blocked: Optional[bool] = None + protection: Optional[dict[str, bool]] = None @define(eq=False, slots=False) -class HcloudIso(HcloudResource): - kind: ClassVar[str] = "hcloud_iso" +class HcloudFirewall(HcloudResource): + kind: ClassVar[str] = "hcloud_firewall" + + +@define(eq=False, slots=False) +class HcloudPrimaryIP(BaseIPAddress, HcloudResource): + kind: ClassVar[str] = "hcloud_primary_ip" + + dns_ptr: Optional[Union[str, list[dict[str, str]]]] = None + blocked: Optional[bool] = None + protection: Optional[dict[str, bool]] = None + assignee_id: Optional[int] = None + assigneer_type: Optional[str] = None + auto_delete: Optional[bool] = None + + +@define(eq=False, slots=False) +class HcloudPublicNetwork: + kind: ClassVar[str] = "hcloud_public_network" + + ipv4: Optional[HcloudIPv4Address] = None + ipv6: Optional[HcloudIPv6Network] = None + + +@define(eq=False, slots=False) +class HcloudPrivateNetwork: + kind: ClassVar[str] = "hcloud_private_network" + + ip_address: Optional[str] = None + alias_ips: Optional[list[str]] = None + mac_address: Optional[str] = None + + +@define(eq=False, slots=False) +class HcloudDeprecationInfo: + kind: ClassVar[str] = "hcloud_deprecation_info" + + announced_at: Optional[datetime] = None + unavailable_after: Optional[datetime] = None + + +@define(eq=False, slots=False) +class HcloudServerType(BaseInstanceType, HcloudResource): + kind: ClassVar[str] = "hcloud_server_type" + + description: Optional[str] = None + volume_size: Optional[int] = None + prices: Optional[list[dict[str, Union[str, float, dict[str, Union[str, float]]]]]] = None + storage_type: Optional[str] = None + cpu_type: Optional[str] = None + architecture: Optional[str] = None + deprecated: Optional[bool] = None + deprecation: Optional[HcloudDeprecationInfo] = None + included_traffic: Optional[int] = None @define(eq=False, slots=False) @@ -73,8 +146,33 @@ class HcloudVolume(BaseVolume, HcloudResource): @define(eq=False, slots=False) -class HcloudPrivateNet(BaseNetwork, HcloudResource): - kind: ClassVar[str] = "hcloud_private_net" +class HcloudSubnet: + kind: ClassVar[str] = "hcloud_subnet" + + type: Optional[str] = None + ip_range: Optional[str] = None + network_zone: Optional[str] = None + gateway: Optional[str] = None + vswitch_id: Optional[int] = None + + +@define(eq=False, slots=False) +class HcloudRoute: + kind: ClassVar[str] = "hcloud_route" + + destination: Optional[str] = None + gateway: Optional[str] = None + + +@define(eq=False, slots=False) +class HcloudNetwork(BaseNetwork, HcloudResource): + kind: ClassVar[str] = "hcloud_network" + + ip_range: Optional[str] = None + network_subnets: Optional[list[HcloudSubnet]] = None + network_routes: Optional[list[HcloudRoute]] = None + expose_routes_to_vswitch: Optional[bool] = None + protection: Optional[dict[str, bool]] = None @define(eq=False, slots=False) @@ -89,3 +187,36 @@ class HcloudServer(BaseInstance, HcloudResource): included_traffic: Optional[int] = None primary_disk_size: Optional[int] = None protection: Optional[dict[str, bool]] = None + public_net: Optional[HcloudPublicNetwork] = None + private_net: Optional[list[HcloudPrivateNetwork]] = None + + +@define(eq=False, slots=False) +class HcloudIso(HcloudResource): + kind: ClassVar[str] = "hcloud_iso" + + description: Optional[str] = None + type: Optional[str] = None + architecture: Optional[str] = None + deprecated_at: Optional[datetime] = None + deprecation: Optional[HcloudDeprecationInfo] = None + + +@define(eq=False, slots=False) +class HcloudImage(HcloudResource): + kind: ClassVar[str] = "hcloud_image" + + type: Optional[str] = None + status: Optional[str] = None + description: Optional[str] = None + image_size: Optional[float] = None + disk_size: Optional[float] = None + created_at: Optional[datetime] = None + created_from: Optional[HcloudServer] = None + bound_to: Optional[HcloudServer] = None + os_flavor: Optional[str] = None + os_version: Optional[str] = None + architecture: Optional[str] = None + rapid_deploy: Optional[bool] = None + protection: Optional[dict[str, bool]] = None + deprecated_at: Optional[datetime] = None From ac3116de129da8ce0e96d2b56e6ed36cecb67173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 09:15:07 +0200 Subject: [PATCH 09/20] Fix tests --- .../hetzner/fix_plugin_hetzner/__init__.py | 3 - .../hetzner/fix_plugin_hetzner/collector.py | 111 +++++++++++++----- .../hetzner/fix_plugin_hetzner/resources.py | 34 +++++- 3 files changed, 114 insertions(+), 34 deletions(-) diff --git a/plugins/hetzner/fix_plugin_hetzner/__init__.py b/plugins/hetzner/fix_plugin_hetzner/__init__.py index 8ed3cf1ab6..08a27165d5 100644 --- a/plugins/hetzner/fix_plugin_hetzner/__init__.py +++ b/plugins/hetzner/fix_plugin_hetzner/__init__.py @@ -1,4 +1,3 @@ -import fixlib.logger from fixlib.baseplugin import BaseCollectorPlugin from fixlib.args import ArgumentParser from fixlib.config import Config @@ -11,8 +10,6 @@ from .collector import HcloudCollector from .resources import HcloudProject -log = fixlib.logger.getLogger("fix." + __name__) - class HetznerCollectorPlugin(BaseCollectorPlugin): cloud = "hetzner" diff --git a/plugins/hetzner/fix_plugin_hetzner/collector.py b/plugins/hetzner/fix_plugin_hetzner/collector.py index 508e452c4a..2690bb8140 100644 --- a/plugins/hetzner/fix_plugin_hetzner/collector.py +++ b/plugins/hetzner/fix_plugin_hetzner/collector.py @@ -13,7 +13,6 @@ HcloudSubnet, HcloudRoute, HcloudIso, - HcloudImage, HcloudDeprecationInfo, HcloudServerType, HcloudFloatingIP, @@ -22,7 +21,8 @@ HcloudPublicNetwork, HcloudIPv4Address, HcloudIPv6Network, - HcloudPrimaryIP, + HcloudFirewall, + HcloudFirewallRule, ) from .client import get_client @@ -54,12 +54,13 @@ def collect(self): self.add_servers() self.add_networks() self.add_floating_ips() + self.add_firewalls() def add_locations(self): log.info(f"Collecting locations in {self.project.kdname}") client = get_client(self.api_token) for location in client.locations.get_all(): - l = HcloudLocation( + hcl = HcloudLocation( hcloud_id=location.id, id=location.name, name=location.name, @@ -69,14 +70,14 @@ def add_locations(self): cloud=self.cloud, account=self.project, ) - self.graph.add_resource(self.project, l) + self.graph.add_resource(self.project, hcl) def add_datacenters(self): log.info(f"Collecting datacenters in {self.project.kdname}") client = get_client(self.api_token) for datacenter in client.datacenters.get_all(): - l = self.graph.search_first_all({"kind": "hcloud_location", "id": datacenter.location.name}) - if not l: + hcl = self.graph.search_first_all({"kind": "hcloud_location", "id": datacenter.location.name}) + if not hcl: log.error(f"Location {datacenter.location.name} not found for datacenter {datacenter.name}") continue d = HcloudDatacenter( @@ -86,15 +87,15 @@ def add_datacenters(self): long_name=datacenter.description, cloud=self.cloud, account=self.project, - region=l, + region=hcl, ) - self.graph.add_resource(l, d) + self.graph.add_resource(hcl, d) def add_networks(self): log.info(f"Collecting networks in {self.project.kdname}") client = get_client(self.api_token) for network in client.networks.get_all(): - n = HcloudNetwork( + hcn = HcloudNetwork( hcloud_id=network.id, id=network.name, name=network.name, @@ -116,20 +117,20 @@ def add_networks(self): expose_routes_to_vswitch=network.expose_routes_to_vswitch, protection=network.protection, ) - self.graph.add_resource(self.project, n) + self.graph.add_resource(self.project, hcn) for server in network.servers: - s = self.graph.search_first_all({"kind": "hcloud_server", "id": server.name}) - if not s: + hcs = self.graph.search_first_all({"kind": "hcloud_server", "id": server.name}) + if not hcs: log.error(f"Server {server.name} not found for network {network.name}") continue - self.graph.add_edge(n, s) + self.graph.add_edge(hcn, hcs) def add_volumes(self): log.info(f"Collecting volumes in {self.project.kdname}") client = get_client(self.api_token) for volume in client.volumes.get_all(): - l = self.graph.search_first_all({"kind": "hcloud_location", "id": volume.location.name}) - if not l: + hcl = self.graph.search_first_all({"kind": "hcloud_location", "id": volume.location.name}) + if not hcl: log.error(f"Location {volume.location.name} not found for volume {volume.name}") continue @@ -142,7 +143,7 @@ def add_volumes(self): elif volume.status == "creating": volume_status = VolumeStatus.BUSY - v = HcloudVolume( + hcv = HcloudVolume( hcloud_id=volume.id, id=volume.name, name=volume.name, @@ -155,28 +156,29 @@ def add_volumes(self): format=volume.format, cloud=self.cloud, account=self.project, - region=l, + region=hcl, ) - self.graph.add_resource(l, v) + self.graph.add_resource(hcl, hcv) def add_servers(self): log.info(f"Collecting servers in {self.project.kdname}") client = get_client(self.api_token) for server in client.servers.get_all(): - d = self.graph.search_first_all({"kind": "hcloud_datacenter", "id": server.datacenter.name}) - if not d: + hcd = self.graph.search_first_all({"kind": "hcloud_datacenter", "id": server.datacenter.name}) + if not hcd: log.error(f"Datacenter {server.datacenter.name} not found for server {server.name}") continue - l = d.region() + hcl = hcd.region() public_net = None - floating_ips = None + instance_cores = None + instance_memory = None + instance_type = None if server.public_net: ipv4 = None ipv6 = None primary_ipv4 = None primary_ipv6 = None - firewalls = None if server.public_net.ipv4: ipv4 = HcloudIPv4Address( ip_address=server.public_net.ipv4.ip, @@ -208,12 +210,24 @@ def add_servers(self): private_net = [] private_net.append(pn) + st = None + if server.server_type: + st: HcloudServerType = self.graph.search_first_all( + {"kind": "hcloud_server_type", "id": server.server_type.name} + ) + if st: + instance_cores = st.instance_cores + instance_memory = st.instance_memory + instance_type = st.name s = HcloudServer( hcloud_id=server.id, id=server.name, name=server.name, ctime=server.created, tags=server.labels, + instance_cores=instance_cores, + instance_memory=instance_memory, + instance_type=instance_type, public_net=public_net, private_net=private_net, rescue_enabled=server.rescue_enabled, @@ -226,11 +240,13 @@ def add_servers(self): protection=server.protection, cloud=self.cloud, account=self.project, - region=l, - zone=d, + region=hcl, + zone=hcd, ) - self.graph.add_resource(l, s) - self.graph.add_edge(d, s) + self.graph.add_resource(hcl, s) + self.graph.add_edge(hcd, s) + if st: + self.graph.add_edge(st, s) for volume in server.volumes: v = self.graph.search_first_all({"kind": "hcloud_volume", "id": volume.name}) if not v: @@ -308,7 +324,7 @@ def add_floating_ips(self): log.info(f"Collecting floating IPs in {self.project.kdname}") client = get_client(self.api_token) for floating_ip in client.floating_ips.get_all(): - l = self.graph.search_first_all({"kind": "hcloud_location", "id": floating_ip.home_location.name}) + hcl = self.graph.search_first_all({"kind": "hcloud_location", "id": floating_ip.home_location.name}) fi = HcloudFloatingIP( hcloud_id=floating_ip.id, id=floating_ip.ip, @@ -317,7 +333,7 @@ def add_floating_ips(self): ctime=floating_ip.created, cloud=self.cloud, account=self.project, - region=l, + region=hcl, description=floating_ip.description, ip_address=floating_ip.ip, ip_address_family=floating_ip.type, @@ -325,7 +341,7 @@ def add_floating_ips(self): dns_ptr=floating_ip.dns_ptr, protection=floating_ip.protection, ) - self.graph.add_resource(l, fi) + self.graph.add_resource(hcl, fi) if floating_ip.server: s = self.graph.search_first_all({"kind": "hcloud_server", "id": floating_ip.server.name}) if s: @@ -357,3 +373,38 @@ def add_primary_ips(self): protection=primary_ip.protection, ) self.graph.add_resource(r, p) + + def add_firewalls(self): + log.info(f"Collecting firewalls in {self.project.kdname}") + client = get_client(self.api_token) + for firewall in client.firewalls.get_all(): + rules = None + if firewall.rules: + firewall_rules = [ + HcloudFirewallRule( + direction=r.direction, + port=r.port, + protocol=r.protocol, + source_ips=r.source_ips, + destination_ips=r.destination_ips, + description=r.description, + ) + for r in firewall.rules + ] + f = HcloudFirewall( + hcloud_id=firewall.id, + id=firewall.name, + name=firewall.name, + tags=firewall.labels, + ctime=firewall.created, + cloud=self.cloud, + account=self.project, + firewall_rules=firewall_rules, + ) + self.graph.add_resource(self.project, f) + if firewall.applied_to: + for firewall_resource in firewall.applied_to: + if firewall_resource.type == "server": + s = self.graph.search_first_all({"kind": "hcloud_server", "id": firewall_resource.server.name}) + if s: + self.graph.add_edge(f, s) diff --git a/plugins/hetzner/fix_plugin_hetzner/resources.py b/plugins/hetzner/fix_plugin_hetzner/resources.py index 0afe21893d..7efe07dcea 100644 --- a/plugins/hetzner/fix_plugin_hetzner/resources.py +++ b/plugins/hetzner/fix_plugin_hetzner/resources.py @@ -12,6 +12,8 @@ BaseVolume, BaseInstanceType, BaseIPAddress, + BaseFirewall, + BaseLoadBalancer, ) @@ -80,9 +82,23 @@ class HcloudFloatingIP(BaseIPAddress, HcloudResource): @define(eq=False, slots=False) -class HcloudFirewall(HcloudResource): +class HcloudFirewallRule: + kind: ClassVar[str] = "hcloud_firewall_rule" + + direction: Optional[str] = None + port: Optional[str] = None + protocol: Optional[str] = None + source_ips: Optional[list[str]] = None + destination_ips: Optional[list[str]] = None + description: Optional[str] = None + + +@define(eq=False, slots=False) +class HcloudFirewall(BaseFirewall, HcloudResource): kind: ClassVar[str] = "hcloud_firewall" + firewall_rules: Optional[list[HcloudFirewallRule]] = None + @define(eq=False, slots=False) class HcloudPrimaryIP(BaseIPAddress, HcloudResource): @@ -220,3 +236,19 @@ class HcloudImage(HcloudResource): rapid_deploy: Optional[bool] = None protection: Optional[dict[str, bool]] = None deprecated_at: Optional[datetime] = None + + +@define(eq=False, slots=False) +class HcloudLoadBalancer(BaseLoadBalancer, HcloudResource): + kind: ClassVar[str] = "hcloud_load_balancer" + + protection: Optional[dict[str, bool]] = None + public_net: Optional[HcloudPublicNetwork] = None + private_net: Optional[list[HcloudPrivateNetwork]] = None + algorithm: Optional[str] = None + services: Optional[list[dict[str, Union[str, int, list[str]]]]] = None + targets: Optional[list[dict[str, Union[str, int, list[str]]]]] = None + load_balancer_type: Optional[str] = None + outgoing_traffic: Optional[int] = None + ingoing_traffic: Optional[int] = None + included_traffic: Optional[int] = None From 5a4840c871081c9f2ffe213d58831abf41fe1e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 09:16:13 +0200 Subject: [PATCH 10/20] Remove unused imports --- plugins/hetzner/fix_plugin_hetzner/config.py | 6 +++--- .../hetzner/fix_plugin_hetzner/resources.py | 19 +------------------ 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/plugins/hetzner/fix_plugin_hetzner/config.py b/plugins/hetzner/fix_plugin_hetzner/config.py index 4f81d1cd1a..5f749d4ca6 100644 --- a/plugins/hetzner/fix_plugin_hetzner/config.py +++ b/plugins/hetzner/fix_plugin_hetzner/config.py @@ -9,9 +9,9 @@ class HetznerConfig: factory=list, metadata={ "description": ( - "Hetzner Cloud project names - Hetzner has no API to introspect a token, so you need to manually maintain" - " the project name associated with an API token. Provide names in the same order as the corresponding API" - " tokens." + "Hetzner Cloud project names - Hetzner has no API to introspect a token, so you need" + " to manually maintain the project name associated with an API token. Provide names" + " in the same order as the corresponding API tokens." ) }, ) diff --git a/plugins/hetzner/fix_plugin_hetzner/resources.py b/plugins/hetzner/fix_plugin_hetzner/resources.py index 7efe07dcea..dbd4514044 100644 --- a/plugins/hetzner/fix_plugin_hetzner/resources.py +++ b/plugins/hetzner/fix_plugin_hetzner/resources.py @@ -1,5 +1,5 @@ from attrs import define -from typing import ClassVar, Optional, Union, Any +from typing import ClassVar, Optional, Union from datetime import datetime from fixlib.graph import Graph from fixlib.baseresources import ( @@ -13,7 +13,6 @@ BaseInstanceType, BaseIPAddress, BaseFirewall, - BaseLoadBalancer, ) @@ -236,19 +235,3 @@ class HcloudImage(HcloudResource): rapid_deploy: Optional[bool] = None protection: Optional[dict[str, bool]] = None deprecated_at: Optional[datetime] = None - - -@define(eq=False, slots=False) -class HcloudLoadBalancer(BaseLoadBalancer, HcloudResource): - kind: ClassVar[str] = "hcloud_load_balancer" - - protection: Optional[dict[str, bool]] = None - public_net: Optional[HcloudPublicNetwork] = None - private_net: Optional[list[HcloudPrivateNetwork]] = None - algorithm: Optional[str] = None - services: Optional[list[dict[str, Union[str, int, list[str]]]]] = None - targets: Optional[list[dict[str, Union[str, int, list[str]]]]] = None - load_balancer_type: Optional[str] = None - outgoing_traffic: Optional[int] = None - ingoing_traffic: Optional[int] = None - included_traffic: Optional[int] = None From ac135d641825f430924085cc3a3f8c8bb55aeee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 09:18:05 +0200 Subject: [PATCH 11/20] Remove unused vars --- plugins/hetzner/fix_plugin_hetzner/collector.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/hetzner/fix_plugin_hetzner/collector.py b/plugins/hetzner/fix_plugin_hetzner/collector.py index 2690bb8140..9b9265d27f 100644 --- a/plugins/hetzner/fix_plugin_hetzner/collector.py +++ b/plugins/hetzner/fix_plugin_hetzner/collector.py @@ -378,7 +378,6 @@ def add_firewalls(self): log.info(f"Collecting firewalls in {self.project.kdname}") client = get_client(self.api_token) for firewall in client.firewalls.get_all(): - rules = None if firewall.rules: firewall_rules = [ HcloudFirewallRule( From 539ae662883359fc9b7ab4bb864ecc72d46ef354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 09:21:21 +0200 Subject: [PATCH 12/20] Update README --- plugins/hetzner/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/hetzner/README.md b/plugins/hetzner/README.md index 422a0849d2..ff64c7bc1d 100644 --- a/plugins/hetzner/README.md +++ b/plugins/hetzner/README.md @@ -2,6 +2,24 @@ Hetzner Collector Plugin for Fix +## Configuration + +``` +fixworker: + # List of collectors to run + collector: + - 'hetzner' +hetzner: + # Hetzner Cloud project names - Hetzner has no API to introspect a token, so you need to manually maintain the project name associated with an API token. Provide names in the same order as the corresponding API tokens. + hcloud_project_names: + - 'dev' + - 'global' + # Hetzner Cloud project API tokens + hcloud_tokens: + - '0ytCtPtcyUO1fEwLIYarEQaiY04E9P9tDIowK1JD8mX5K5jsLhPmiwkMLLuDGMxG' + - 'nt71Kl3pSscVt5Mey1NUfERXeaxHyDru988De7UA4ew48eAvMMsQ8tserBEOwLXq' +``` + ## License See [LICENSE](../../LICENSE) for details. From 8c350915c5c3dd629d156bcef03de892a46e0be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 09:22:56 +0200 Subject: [PATCH 13/20] Bump actions/upload-artifact --- .github/workflows/check_pr_plugin_hetzner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_pr_plugin_hetzner.yml b/.github/workflows/check_pr_plugin_hetzner.yml index 8876b536c6..b85469a1c4 100644 --- a/.github/workflows/check_pr_plugin_hetzner.yml +++ b/.github/workflows/check_pr_plugin_hetzner.yml @@ -48,7 +48,7 @@ jobs: run: tox - name: Archive code coverage results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: plugin-hetzner-code-coverage-report path: ./plugins/hetzner/htmlcov/ From 2bcbf596f6a0d7f4fcbe2e83a7f29cf2ac767836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 09:26:36 +0200 Subject: [PATCH 14/20] Add concurrency to workflows --- .github/workflows/check_pr_fixlib.yml | 3 +++ .github/workflows/check_pr_fixmetrics.yml | 4 ++++ .github/workflows/check_pr_fixshell.yml | 4 ++++ .github/workflows/check_pr_fixworker.yml | 4 ++++ .github/workflows/check_pr_plugin_aws.yml | 4 ++++ .github/workflows/check_pr_plugin_azure.yml | 4 ++++ .github/workflows/check_pr_plugin_digitalocean.yml | 4 ++++ .github/workflows/check_pr_plugin_dockerhub.yml | 4 ++++ .github/workflows/check_pr_plugin_example_collector.yml | 4 ++++ .github/workflows/check_pr_plugin_gcp.yml | 4 ++++ .github/workflows/check_pr_plugin_github.yml | 4 ++++ .github/workflows/check_pr_plugin_hetzner.yml | 4 ++++ .github/workflows/check_pr_plugin_k8s.yml | 4 ++++ .github/workflows/check_pr_plugin_onelogin.yml | 4 ++++ .github/workflows/check_pr_plugin_onprem.yml | 4 ++++ .github/workflows/check_pr_plugin_posthog.yml | 4 ++++ .github/workflows/check_pr_plugin_random.yml | 4 ++++ .github/workflows/check_pr_plugin_scarf.yml | 4 ++++ .github/workflows/check_pr_plugin_slack.yml | 4 ++++ .github/workflows/check_pr_plugin_vsphere.yml | 4 ++++ .github/workflows/create_plugin_workflows.py | 4 ++++ .github/workflows/fixcore_test_and_build.yml | 4 ++++ 22 files changed, 87 insertions(+) diff --git a/.github/workflows/check_pr_fixlib.yml b/.github/workflows/check_pr_fixlib.yml index 01922f16c4..c969e34968 100644 --- a/.github/workflows/check_pr_fixlib.yml +++ b/.github/workflows/check_pr_fixlib.yml @@ -10,6 +10,9 @@ on: - 'fixlib/**' - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: fixlib: diff --git a/.github/workflows/check_pr_fixmetrics.yml b/.github/workflows/check_pr_fixmetrics.yml index ebf7c74fd5..e718824482 100644 --- a/.github/workflows/check_pr_fixmetrics.yml +++ b/.github/workflows/check_pr_fixmetrics.yml @@ -12,6 +12,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: fixmetrics: name: "fixmetrics" diff --git a/.github/workflows/check_pr_fixshell.yml b/.github/workflows/check_pr_fixshell.yml index 9993cb2bf5..f2e0f118a0 100644 --- a/.github/workflows/check_pr_fixshell.yml +++ b/.github/workflows/check_pr_fixshell.yml @@ -13,6 +13,10 @@ on: - 'requirements-all.txt' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: fixshell: name: "fixshell" diff --git a/.github/workflows/check_pr_fixworker.yml b/.github/workflows/check_pr_fixworker.yml index cc700b04b5..684a9308d7 100644 --- a/.github/workflows/check_pr_fixworker.yml +++ b/.github/workflows/check_pr_fixworker.yml @@ -12,6 +12,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: fixworker: name: "fixworker" diff --git a/.github/workflows/check_pr_plugin_aws.yml b/.github/workflows/check_pr_plugin_aws.yml index f15cedadb0..b22ee47ca9 100644 --- a/.github/workflows/check_pr_plugin_aws.yml +++ b/.github/workflows/check_pr_plugin_aws.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: aws: name: "aws" diff --git a/.github/workflows/check_pr_plugin_azure.yml b/.github/workflows/check_pr_plugin_azure.yml index 39f6f697e1..75d483489a 100644 --- a/.github/workflows/check_pr_plugin_azure.yml +++ b/.github/workflows/check_pr_plugin_azure.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: azure: name: "azure" diff --git a/.github/workflows/check_pr_plugin_digitalocean.yml b/.github/workflows/check_pr_plugin_digitalocean.yml index 9bfe0cbf71..4802c7765d 100644 --- a/.github/workflows/check_pr_plugin_digitalocean.yml +++ b/.github/workflows/check_pr_plugin_digitalocean.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: digitalocean: name: "digitalocean" diff --git a/.github/workflows/check_pr_plugin_dockerhub.yml b/.github/workflows/check_pr_plugin_dockerhub.yml index 34a87324d8..c8bc12c5cc 100644 --- a/.github/workflows/check_pr_plugin_dockerhub.yml +++ b/.github/workflows/check_pr_plugin_dockerhub.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: dockerhub: name: "dockerhub" diff --git a/.github/workflows/check_pr_plugin_example_collector.yml b/.github/workflows/check_pr_plugin_example_collector.yml index b6f3a9e7c8..60520deb80 100644 --- a/.github/workflows/check_pr_plugin_example_collector.yml +++ b/.github/workflows/check_pr_plugin_example_collector.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: example_collector: name: "example_collector" diff --git a/.github/workflows/check_pr_plugin_gcp.yml b/.github/workflows/check_pr_plugin_gcp.yml index b797cbde00..50520b5a45 100644 --- a/.github/workflows/check_pr_plugin_gcp.yml +++ b/.github/workflows/check_pr_plugin_gcp.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: gcp: name: "gcp" diff --git a/.github/workflows/check_pr_plugin_github.yml b/.github/workflows/check_pr_plugin_github.yml index 54f54af2d6..335f5196b2 100644 --- a/.github/workflows/check_pr_plugin_github.yml +++ b/.github/workflows/check_pr_plugin_github.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: github: name: "github" diff --git a/.github/workflows/check_pr_plugin_hetzner.yml b/.github/workflows/check_pr_plugin_hetzner.yml index b85469a1c4..da84ef3d3a 100644 --- a/.github/workflows/check_pr_plugin_hetzner.yml +++ b/.github/workflows/check_pr_plugin_hetzner.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: hetzner: name: "hetzner" diff --git a/.github/workflows/check_pr_plugin_k8s.yml b/.github/workflows/check_pr_plugin_k8s.yml index 8c9d8cb09a..b0d776b40f 100644 --- a/.github/workflows/check_pr_plugin_k8s.yml +++ b/.github/workflows/check_pr_plugin_k8s.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: k8s: name: "k8s" diff --git a/.github/workflows/check_pr_plugin_onelogin.yml b/.github/workflows/check_pr_plugin_onelogin.yml index e862bedfd6..7117f344f2 100644 --- a/.github/workflows/check_pr_plugin_onelogin.yml +++ b/.github/workflows/check_pr_plugin_onelogin.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: onelogin: name: "onelogin" diff --git a/.github/workflows/check_pr_plugin_onprem.yml b/.github/workflows/check_pr_plugin_onprem.yml index f97ad794ce..3cea196300 100644 --- a/.github/workflows/check_pr_plugin_onprem.yml +++ b/.github/workflows/check_pr_plugin_onprem.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: onprem: name: "onprem" diff --git a/.github/workflows/check_pr_plugin_posthog.yml b/.github/workflows/check_pr_plugin_posthog.yml index ad452faea3..e7158fc53d 100644 --- a/.github/workflows/check_pr_plugin_posthog.yml +++ b/.github/workflows/check_pr_plugin_posthog.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: posthog: name: "posthog" diff --git a/.github/workflows/check_pr_plugin_random.yml b/.github/workflows/check_pr_plugin_random.yml index 2be2525c4a..2656ce8c98 100644 --- a/.github/workflows/check_pr_plugin_random.yml +++ b/.github/workflows/check_pr_plugin_random.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: random: name: "random" diff --git a/.github/workflows/check_pr_plugin_scarf.yml b/.github/workflows/check_pr_plugin_scarf.yml index 8dd3d107e9..7405db67ae 100644 --- a/.github/workflows/check_pr_plugin_scarf.yml +++ b/.github/workflows/check_pr_plugin_scarf.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: scarf: name: "scarf" diff --git a/.github/workflows/check_pr_plugin_slack.yml b/.github/workflows/check_pr_plugin_slack.yml index ce81d43af3..4e55ac3f83 100644 --- a/.github/workflows/check_pr_plugin_slack.yml +++ b/.github/workflows/check_pr_plugin_slack.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: slack: name: "slack" diff --git a/.github/workflows/check_pr_plugin_vsphere.yml b/.github/workflows/check_pr_plugin_vsphere.yml index ef59159192..0cbb48f80c 100644 --- a/.github/workflows/check_pr_plugin_vsphere.yml +++ b/.github/workflows/check_pr_plugin_vsphere.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: vsphere: name: "vsphere" diff --git a/.github/workflows/create_plugin_workflows.py b/.github/workflows/create_plugin_workflows.py index 76380cf1e7..ead7764721 100755 --- a/.github/workflows/create_plugin_workflows.py +++ b/.github/workflows/create_plugin_workflows.py @@ -21,6 +21,10 @@ - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: @name@: name: "@name@" diff --git a/.github/workflows/fixcore_test_and_build.yml b/.github/workflows/fixcore_test_and_build.yml index edb6a019ad..0d669da52c 100644 --- a/.github/workflows/fixcore_test_and_build.yml +++ b/.github/workflows/fixcore_test_and_build.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: fixcore-test-and-build: name: "Test and build (fixcore)" From d51a717f511c8a7fce95c78b25313f917dc3a32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 10:11:13 +0200 Subject: [PATCH 15/20] Update README --- plugins/hetzner/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/hetzner/README.md b/plugins/hetzner/README.md index ff64c7bc1d..34f84d9f4d 100644 --- a/plugins/hetzner/README.md +++ b/plugins/hetzner/README.md @@ -1,6 +1,12 @@ # fix-plugin-hetzner -Hetzner Collector Plugin for Fix +Hetzner Collector Plugin for Fix (alpha) + +This collector is in alpha stage and may not work as expected. Use at your own risk. + +[x] Resource collection +[ ] Resource deletion +[ ] Tag update ## Configuration From f5a68fa64b7b1c9fd5c01a40a7b21dcc306c1d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 10:12:32 +0200 Subject: [PATCH 16/20] Update README --- plugins/hetzner/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/hetzner/README.md b/plugins/hetzner/README.md index 34f84d9f4d..63a5feb024 100644 --- a/plugins/hetzner/README.md +++ b/plugins/hetzner/README.md @@ -4,9 +4,9 @@ Hetzner Collector Plugin for Fix (alpha) This collector is in alpha stage and may not work as expected. Use at your own risk. -[x] Resource collection -[ ] Resource deletion -[ ] Tag update +- [x] Resource collection +- [ ] Resource deletion +- [ ] Tag update ## Configuration From d8b045c1921ce73f80b5809c1a73b0e132dc86a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 10:13:37 +0200 Subject: [PATCH 17/20] Update README --- plugins/hetzner/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/hetzner/README.md b/plugins/hetzner/README.md index 63a5feb024..8faac5a479 100644 --- a/plugins/hetzner/README.md +++ b/plugins/hetzner/README.md @@ -10,13 +10,13 @@ This collector is in alpha stage and may not work as expected. Use at your own r ## Configuration +Hetzner has no API to introspect a token, so you need to manually maintain the project name associated with an API token. Provide names in the same order as the corresponding API tokens. + ``` fixworker: - # List of collectors to run collector: - 'hetzner' hetzner: - # Hetzner Cloud project names - Hetzner has no API to introspect a token, so you need to manually maintain the project name associated with an API token. Provide names in the same order as the corresponding API tokens. hcloud_project_names: - 'dev' - 'global' From e3a9bf71e06c5c64fba45ac7b741a31580899512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 10:14:15 +0200 Subject: [PATCH 18/20] Update README --- plugins/hetzner/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/hetzner/README.md b/plugins/hetzner/README.md index 8faac5a479..6cfcea76bc 100644 --- a/plugins/hetzner/README.md +++ b/plugins/hetzner/README.md @@ -20,7 +20,6 @@ hetzner: hcloud_project_names: - 'dev' - 'global' - # Hetzner Cloud project API tokens hcloud_tokens: - '0ytCtPtcyUO1fEwLIYarEQaiY04E9P9tDIowK1JD8mX5K5jsLhPmiwkMLLuDGMxG' - 'nt71Kl3pSscVt5Mey1NUfERXeaxHyDru988De7UA4ew48eAvMMsQ8tserBEOwLXq' From 1410f6f3688d40ea4a8f2fc2f92d8976eb597976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 10:16:36 +0200 Subject: [PATCH 19/20] More workflow updates --- .github/workflows/basecheck.yml | 4 ++++ .github/workflows/check_pr_fixlib.yml | 1 + .github/workflows/codeql-analysis.yml | 4 ++++ .github/workflows/docker-build.yml | 4 ++++ .github/workflows/fixcore_coverage.yml | 4 ++++ .github/workflows/fixcore_lint.yml | 4 ++++ .github/workflows/model_check.yml | 4 ++++ 7 files changed, 25 insertions(+) diff --git a/.github/workflows/basecheck.yml b/.github/workflows/basecheck.yml index e7488afdc0..df002df376 100644 --- a/.github/workflows/basecheck.yml +++ b/.github/workflows/basecheck.yml @@ -10,6 +10,10 @@ on: - 'fixlib/**' - 'plugins/**' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: basecheck: name: "basecheck" diff --git a/.github/workflows/check_pr_fixlib.yml b/.github/workflows/check_pr_fixlib.yml index c969e34968..6251d2aecb 100644 --- a/.github/workflows/check_pr_fixlib.yml +++ b/.github/workflows/check_pr_fixlib.yml @@ -10,6 +10,7 @@ on: - 'fixlib/**' - '.github/**' - 'requirements-all.txt' + concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 249d40f6dd..ada56b81c5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -8,6 +8,10 @@ on: schedule: - cron: '26 0 * * 1' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index a4b34c35c5..3e0dd23ed9 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -15,6 +15,10 @@ on: - "requirements-all.txt" workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: split-build: name: "Build split Docker images" # Do not rename without updating workflow defined in publish.yml diff --git a/.github/workflows/fixcore_coverage.yml b/.github/workflows/fixcore_coverage.yml index da3771b574..ccab107060 100644 --- a/.github/workflows/fixcore_coverage.yml +++ b/.github/workflows/fixcore_coverage.yml @@ -15,6 +15,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: fixcore-coverage: name: "Coverage (fixcore)" diff --git a/.github/workflows/fixcore_lint.yml b/.github/workflows/fixcore_lint.yml index 8ca995e394..18a3b28452 100644 --- a/.github/workflows/fixcore_lint.yml +++ b/.github/workflows/fixcore_lint.yml @@ -13,6 +13,10 @@ on: - '.github/**' - 'requirements-all.txt' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: fixcore-lint: name: "Lint (fixcore)" diff --git a/.github/workflows/model_check.yml b/.github/workflows/model_check.yml index 0d1bbd84ab..7552086041 100644 --- a/.github/workflows/model_check.yml +++ b/.github/workflows/model_check.yml @@ -22,6 +22,10 @@ on: - 'requirements-all.txt' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: model: name: "model" From 87ff4d6c000beac625ee306eee631f65c20e4c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 13 Sep 2024 15:11:21 +0200 Subject: [PATCH 20/20] Update concurrency group to either PR number or run ID --- .github/workflows/basecheck.yml | 2 +- .github/workflows/check_pr_fixlib.yml | 2 +- .github/workflows/check_pr_fixmetrics.yml | 2 +- .github/workflows/check_pr_fixshell.yml | 2 +- .github/workflows/check_pr_fixworker.yml | 2 +- .github/workflows/check_pr_plugin_aws.yml | 2 +- .github/workflows/check_pr_plugin_azure.yml | 2 +- .github/workflows/check_pr_plugin_digitalocean.yml | 2 +- .github/workflows/check_pr_plugin_dockerhub.yml | 2 +- .github/workflows/check_pr_plugin_example_collector.yml | 2 +- .github/workflows/check_pr_plugin_gcp.yml | 2 +- .github/workflows/check_pr_plugin_github.yml | 2 +- .github/workflows/check_pr_plugin_hetzner.yml | 2 +- .github/workflows/check_pr_plugin_k8s.yml | 2 +- .github/workflows/check_pr_plugin_onelogin.yml | 2 +- .github/workflows/check_pr_plugin_onprem.yml | 2 +- .github/workflows/check_pr_plugin_posthog.yml | 2 +- .github/workflows/check_pr_plugin_random.yml | 2 +- .github/workflows/check_pr_plugin_scarf.yml | 2 +- .github/workflows/check_pr_plugin_slack.yml | 2 +- .github/workflows/check_pr_plugin_vsphere.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/create_plugin_workflows.py | 2 +- .github/workflows/docker-build.yml | 2 +- .github/workflows/fixcore_coverage.yml | 2 +- .github/workflows/fixcore_lint.yml | 2 +- .github/workflows/fixcore_test_and_build.yml | 2 +- .github/workflows/model_check.yml | 2 +- .github/workflows/publish.yml | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/basecheck.yml b/.github/workflows/basecheck.yml index df002df376..abda4c2679 100644 --- a/.github/workflows/basecheck.yml +++ b/.github/workflows/basecheck.yml @@ -11,7 +11,7 @@ on: - 'plugins/**' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_fixlib.yml b/.github/workflows/check_pr_fixlib.yml index 6251d2aecb..3e89abb13e 100644 --- a/.github/workflows/check_pr_fixlib.yml +++ b/.github/workflows/check_pr_fixlib.yml @@ -12,7 +12,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_fixmetrics.yml b/.github/workflows/check_pr_fixmetrics.yml index e718824482..aa741d9184 100644 --- a/.github/workflows/check_pr_fixmetrics.yml +++ b/.github/workflows/check_pr_fixmetrics.yml @@ -13,7 +13,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_fixshell.yml b/.github/workflows/check_pr_fixshell.yml index f2e0f118a0..697b852bba 100644 --- a/.github/workflows/check_pr_fixshell.yml +++ b/.github/workflows/check_pr_fixshell.yml @@ -14,7 +14,7 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_fixworker.yml b/.github/workflows/check_pr_fixworker.yml index 684a9308d7..984ebdfaee 100644 --- a/.github/workflows/check_pr_fixworker.yml +++ b/.github/workflows/check_pr_fixworker.yml @@ -13,7 +13,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_aws.yml b/.github/workflows/check_pr_plugin_aws.yml index b22ee47ca9..75ffeaff73 100644 --- a/.github/workflows/check_pr_plugin_aws.yml +++ b/.github/workflows/check_pr_plugin_aws.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_azure.yml b/.github/workflows/check_pr_plugin_azure.yml index 75d483489a..ddee301e55 100644 --- a/.github/workflows/check_pr_plugin_azure.yml +++ b/.github/workflows/check_pr_plugin_azure.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_digitalocean.yml b/.github/workflows/check_pr_plugin_digitalocean.yml index 4802c7765d..701bafdc45 100644 --- a/.github/workflows/check_pr_plugin_digitalocean.yml +++ b/.github/workflows/check_pr_plugin_digitalocean.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_dockerhub.yml b/.github/workflows/check_pr_plugin_dockerhub.yml index c8bc12c5cc..2fd52d0a89 100644 --- a/.github/workflows/check_pr_plugin_dockerhub.yml +++ b/.github/workflows/check_pr_plugin_dockerhub.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_example_collector.yml b/.github/workflows/check_pr_plugin_example_collector.yml index 60520deb80..8834c3a2fc 100644 --- a/.github/workflows/check_pr_plugin_example_collector.yml +++ b/.github/workflows/check_pr_plugin_example_collector.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_gcp.yml b/.github/workflows/check_pr_plugin_gcp.yml index 50520b5a45..fbdbac9a49 100644 --- a/.github/workflows/check_pr_plugin_gcp.yml +++ b/.github/workflows/check_pr_plugin_gcp.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_github.yml b/.github/workflows/check_pr_plugin_github.yml index 335f5196b2..3af3b65d46 100644 --- a/.github/workflows/check_pr_plugin_github.yml +++ b/.github/workflows/check_pr_plugin_github.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_hetzner.yml b/.github/workflows/check_pr_plugin_hetzner.yml index da84ef3d3a..2dfd4cd9f1 100644 --- a/.github/workflows/check_pr_plugin_hetzner.yml +++ b/.github/workflows/check_pr_plugin_hetzner.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_k8s.yml b/.github/workflows/check_pr_plugin_k8s.yml index b0d776b40f..5599a12b59 100644 --- a/.github/workflows/check_pr_plugin_k8s.yml +++ b/.github/workflows/check_pr_plugin_k8s.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_onelogin.yml b/.github/workflows/check_pr_plugin_onelogin.yml index 7117f344f2..5f19d7ba5b 100644 --- a/.github/workflows/check_pr_plugin_onelogin.yml +++ b/.github/workflows/check_pr_plugin_onelogin.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_onprem.yml b/.github/workflows/check_pr_plugin_onprem.yml index 3cea196300..5a23e86aa2 100644 --- a/.github/workflows/check_pr_plugin_onprem.yml +++ b/.github/workflows/check_pr_plugin_onprem.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_posthog.yml b/.github/workflows/check_pr_plugin_posthog.yml index e7158fc53d..bc4cbbbc4b 100644 --- a/.github/workflows/check_pr_plugin_posthog.yml +++ b/.github/workflows/check_pr_plugin_posthog.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_random.yml b/.github/workflows/check_pr_plugin_random.yml index 2656ce8c98..e14cd6d474 100644 --- a/.github/workflows/check_pr_plugin_random.yml +++ b/.github/workflows/check_pr_plugin_random.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_scarf.yml b/.github/workflows/check_pr_plugin_scarf.yml index 7405db67ae..a1ae7bef88 100644 --- a/.github/workflows/check_pr_plugin_scarf.yml +++ b/.github/workflows/check_pr_plugin_scarf.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_slack.yml b/.github/workflows/check_pr_plugin_slack.yml index 4e55ac3f83..a27286987b 100644 --- a/.github/workflows/check_pr_plugin_slack.yml +++ b/.github/workflows/check_pr_plugin_slack.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/check_pr_plugin_vsphere.yml b/.github/workflows/check_pr_plugin_vsphere.yml index 0cbb48f80c..748185f40e 100644 --- a/.github/workflows/check_pr_plugin_vsphere.yml +++ b/.github/workflows/check_pr_plugin_vsphere.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ada56b81c5..23148ad2ec 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -9,7 +9,7 @@ on: - cron: '26 0 * * 1' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/create_plugin_workflows.py b/.github/workflows/create_plugin_workflows.py index ead7764721..4e60f75618 100755 --- a/.github/workflows/create_plugin_workflows.py +++ b/.github/workflows/create_plugin_workflows.py @@ -22,7 +22,7 @@ - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 3e0dd23ed9..83f95bf9b7 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -16,7 +16,7 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/fixcore_coverage.yml b/.github/workflows/fixcore_coverage.yml index ccab107060..80cab4ad17 100644 --- a/.github/workflows/fixcore_coverage.yml +++ b/.github/workflows/fixcore_coverage.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/fixcore_lint.yml b/.github/workflows/fixcore_lint.yml index 18a3b28452..0594df6753 100644 --- a/.github/workflows/fixcore_lint.yml +++ b/.github/workflows/fixcore_lint.yml @@ -14,7 +14,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/fixcore_test_and_build.yml b/.github/workflows/fixcore_test_and_build.yml index 0d669da52c..63c70b2a5d 100644 --- a/.github/workflows/fixcore_test_and_build.yml +++ b/.github/workflows/fixcore_test_and_build.yml @@ -16,7 +16,7 @@ on: - 'requirements-all.txt' concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/model_check.yml b/.github/workflows/model_check.yml index 7552086041..ea6fcf1429 100644 --- a/.github/workflows/model_check.yml +++ b/.github/workflows/model_check.yml @@ -23,7 +23,7 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b1f5c02a09..0e26cdb001 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,7 +9,7 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.run_id }} cancel-in-progress: true jobs: