Initial commit: stateful OpenStack API laboratory simulator.
Ship Keystone auth, multi-service handlers (Yoga→Dalmatian), Compose/Helm packaging, API contract packs, and pytest/Pulumi coverage labs.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
"""Seeded deterministic fault-rule evaluation."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class FaultContext:
|
||||
method: str
|
||||
path: str
|
||||
principal: str | None = None
|
||||
node: str | None = None
|
||||
vmid: str | None = None
|
||||
call_number: int = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class FaultRule:
|
||||
kind: str
|
||||
probability: float = 1.0
|
||||
method: str | None = None
|
||||
path_prefix: str | None = None
|
||||
principal: str | None = None
|
||||
node: str | None = None
|
||||
vmid: str | None = None
|
||||
call_number: int | None = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not 0 <= self.probability <= 1:
|
||||
raise ValueError("fault probability must be between zero and one")
|
||||
|
||||
|
||||
def matches(rule: FaultRule, context: FaultContext, seed: int) -> bool:
|
||||
filters = (
|
||||
(rule.method, context.method),
|
||||
(rule.principal, context.principal),
|
||||
(rule.node, context.node),
|
||||
(rule.vmid, context.vmid),
|
||||
(rule.call_number, context.call_number),
|
||||
)
|
||||
if any(expected is not None and expected != actual for expected, actual in filters):
|
||||
return False
|
||||
if rule.path_prefix is not None and not context.path.startswith(rule.path_prefix):
|
||||
return False
|
||||
material = f"{seed}:{rule.kind}:{context.method}:{context.path}:{context.call_number}"
|
||||
sample = int.from_bytes(hashlib.sha256(material.encode()).digest()[:8], "big") / 2**64
|
||||
return sample < rule.probability
|
||||
Reference in New Issue
Block a user