From 51b9a1c84be482031121f1f972a53605174902fc Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Wed, 23 Oct 2024 15:53:10 -0500 Subject: [PATCH] feat: flavor schema for ironic hw detect We'll want to detect and confirm the hardware in Ironic and match it to hardware flavors we want to offer and expect. This schema defines the data files that the flavors hook for Ironic will consume. Changed cpu_models to cpu_model and added support for pci devices list. --- docs/schema/flavor.schema.json | 1 + .../ironic_understack/flavor_spec.py | 18 +++- .../tests/test_flavor_spec.py | 14 ++-- .../ironic_understack/tests/test_matcher.py | 9 +- schema/README.md | 5 ++ schema/flavor.schema.json | 84 +++++++++++++++++++ 6 files changed, 118 insertions(+), 13 deletions(-) create mode 120000 docs/schema/flavor.schema.json create mode 100644 schema/flavor.schema.json diff --git a/docs/schema/flavor.schema.json b/docs/schema/flavor.schema.json new file mode 120000 index 000000000..28bad20bd --- /dev/null +++ b/docs/schema/flavor.schema.json @@ -0,0 +1 @@ +../../schema/flavor.schema.json \ No newline at end of file diff --git a/python/ironic-understack/ironic_understack/flavor_spec.py b/python/ironic-understack/ironic_understack/flavor_spec.py index 8848f80db..30fcd1262 100644 --- a/python/ironic-understack/ironic_understack/flavor_spec.py +++ b/python/ironic-understack/ironic_understack/flavor_spec.py @@ -6,6 +6,14 @@ from ironic_understack.machine import Machine +@dataclass +class PciSpec: + vendor_id: str + device_id: str + sub_vendor_id: str + sub_device_id: str + + @dataclass class FlavorSpec: name: str @@ -13,8 +21,9 @@ class FlavorSpec: model: str memory_gb: int cpu_cores: int - cpu_models: list[str] + cpu_model: str drives: list[int] + pci: list[PciSpec] @staticmethod def from_yaml(yaml_str: str) -> "FlavorSpec": @@ -25,8 +34,9 @@ def from_yaml(yaml_str: str) -> "FlavorSpec": model=data["model"], memory_gb=data["memory_gb"], cpu_cores=data["cpu_cores"], - cpu_models=data["cpu_models"], + cpu_model=data.get("cpu_model", data.get("cpu_models", [""]).pop()), drives=data["drives"], + pci=data.get("pci", []), ) @staticmethod @@ -67,7 +77,7 @@ def score_machine(self, machine: Machine): if ( machine.memory_gb == self.memory_gb and machine.disk_gb in self.drives - and machine.cpu in self.cpu_models + and machine.cpu == self.cpu_model ): return 100 @@ -80,7 +90,7 @@ def score_machine(self, machine: Machine): return 0 # Rule 4: Machine must match the flavor on one of the CPU models exactly - if machine.cpu not in self.cpu_models: + if machine.cpu != self.cpu_model: return 0 # Rule 5 and 6: Rank based on exact matches or excess capacity diff --git a/python/ironic-understack/ironic_understack/tests/test_flavor_spec.py b/python/ironic-understack/ironic_understack/tests/test_flavor_spec.py index 16cdcc8b5..8e06a3bc0 100644 --- a/python/ironic-understack/ironic_understack/tests/test_flavor_spec.py +++ b/python/ironic-understack/ironic_understack/tests/test_flavor_spec.py @@ -14,8 +14,7 @@ def valid_yaml(): model: PowerEdge R7615 memory_gb: 7777 cpu_cores: 245 -cpu_models: - - AMD EPYC 9254 245-Core Processor +cpu_model: AMD EPYC 9254 245-Core Processor drives: - 960 - 960 @@ -50,7 +49,7 @@ def test_from_yaml(valid_yaml): assert spec.model == "PowerEdge R7615" assert spec.memory_gb == 7777 assert spec.cpu_cores == 245 - assert spec.cpu_models == ["AMD EPYC 9254 245-Core Processor"] + assert spec.cpu_model == "AMD EPYC 9254 245-Core Processor" assert spec.drives == [960, 960] @@ -119,8 +118,9 @@ def flavors(): model="Fake Machine", memory_gb=100, cpu_cores=13, - cpu_models=["AMD EPYC 9254 245-Core Processor"], + cpu_model="AMD EPYC 9254 245-Core Processor", drives=[500, 500], + pci=[], ), FlavorSpec( name="medium", @@ -128,8 +128,9 @@ def flavors(): model="Fake Machine", memory_gb=200, cpu_cores=15, - cpu_models=["AMD EPYC 9254 245-Core Processor"], + cpu_model="AMD EPYC 9254 245-Core Processor", drives=[1500, 1500], + pci=[], ), FlavorSpec( name="large", @@ -137,8 +138,9 @@ def flavors(): model="Fake Machine", memory_gb=400, cpu_cores=27, - cpu_models=["AMD EPYC 9254 245-Core Processor"], + cpu_model="AMD EPYC 9254 245-Core Processor", drives=[1800, 1800], + pci=[], ), ] diff --git a/python/ironic-understack/ironic_understack/tests/test_matcher.py b/python/ironic-understack/ironic_understack/tests/test_matcher.py index 89dd22f8d..2e4455fc3 100644 --- a/python/ironic-understack/ironic_understack/tests/test_matcher.py +++ b/python/ironic-understack/ironic_understack/tests/test_matcher.py @@ -13,8 +13,9 @@ def sample_flavors(): model="Fake Machine", memory_gb=4, cpu_cores=2, - cpu_models=["x86"], + cpu_model="x86", drives=[20], + pci=[], ), FlavorSpec( name="medium", @@ -22,8 +23,9 @@ def sample_flavors(): model="Fake Machine", memory_gb=8, cpu_cores=4, - cpu_models=["x86"], + cpu_model="x86", drives=[40], + pci=[], ), FlavorSpec( name="large", @@ -31,8 +33,9 @@ def sample_flavors(): model="Fake Machine", memory_gb=16, cpu_cores=8, - cpu_models=["x86"], + cpu_model="x86", drives=[80], + pci=[], ), ] diff --git a/schema/README.md b/schema/README.md index ff56aec9f..ff0139fb2 100644 --- a/schema/README.md +++ b/schema/README.md @@ -5,3 +5,8 @@ ```bash curl -o argo-workflows.json https://raw.githubusercontent.com/argoproj/argo-workflows/master/api/jsonschema/schema.json ``` + +## flavor.schema + +Used to define hardware identification / mapping for Ironic hardware to Nova flavors. +The flavors hook uses these files to set properties automatically on the nodes. diff --git a/schema/flavor.schema.json b/schema/flavor.schema.json new file mode 100644 index 000000000..397b8c94e --- /dev/null +++ b/schema/flavor.schema.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://rackerlabs.github.io/understack/schema/flavor.schema.json", + "title": "UnderStack Hardware Flavor", + "description": "Server flavor configuration schema", + "type": "object", + "properties": { + "name": { + "description": "Flavor name for specified configuration (ie gp01.s)", + "type": "string" + }, + "manufacturer": { + "description": "Manufacturer of the hardware chassis", + "type": "string" + }, + "model": { + "description": "Model of the hardware chassis", + "type": "string" + }, + "cpu_cores": { + "description": "Total CPU cores.", + "type": "number" + }, + "cpu_model": { + "description": "Processor model", + "type": "string" + }, + "cpu_models": { + "description": "Processor models", + "type": "array", + "items": { + "type": "string", + "description": "Processor model" + }, + "minItems": 1, + "maxItems": 1 + }, + "memory_gb": { + "description": "Total memory in GB", + "type": "number" + }, + "memory_modules": { + "description": "Memory modules", + "type": "array", + "items": { + "type": "number", + "description": "Capacity in GB" + } + }, + "drives": { + "description": "Drives", + "type": "array", + "items": { + "type": "number", + "description": "Capacity in GB" + } + }, + "pci": { + "description": "PCI devices", + "type": "array", + "items": { + "type": "object", + "description": "PCI device", + "properties": { + "vendor_id": { + "type": "string" + }, + "device_id": { + "type": "string" + }, + "sub_vendor_id": { + "type": "string" + }, + "sub_device_id": { + "type": "string" + } + }, + "required": ["vendor_id", "device_id", "sub_vendor_id", "sub_device_id"] + + } + } + }, + "required": [ "name", "manufacturer", "model", "cpu_cores", "cpu_models", "memory_gb", "drives" ] +}