From 2193e33cc688934ad66cbb926ed00b531b4ee8aa Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Tue, 9 Jan 2024 14:11:19 -0500 Subject: [PATCH 1/9] Implement K8sSchemaMatcher class --- acto/input/k8s_schemas.py | 346 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 acto/input/k8s_schemas.py diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py new file mode 100644 index 0000000000..6cc1b41592 --- /dev/null +++ b/acto/input/k8s_schemas.py @@ -0,0 +1,346 @@ +from abc import ABC, abstractmethod +from typing import Callable + +import requests + +from acto.schema import ( + AnyOfSchema, + ArraySchema, + BaseSchema, + BooleanSchema, + IntegerSchema, + NumberSchema, + ObjectSchema, + OpaqueSchema, + StringSchema, +) + + +class KubernetesSchema(ABC): + """Base class for Kubernetes schema matching""" + + @abstractmethod + def match(self, schema: BaseSchema) -> bool: + """Determines if the schema matches the Kubernetes schema""" + ... + + @abstractmethod + def dump_schema(self) -> dict: + """Dumps the Kubernetes schema into a dictionary (for debugging)""" + ... + + +class KubernetesObjectSchema(KubernetesSchema): + def __init__(self, schema_name, schema_spec) -> None: + self.k8s_schema_name: str = schema_name + self.schema_spec = schema_spec + self.properties: dict[str, KubernetesSchema] = {} + + def update(self, resolve: Callable[[dict], "KubernetesSchema"]) -> None: + """Resolves k8s schema properties into k8s schema objects""" + if "properties" not in self.schema_spec: + return + for property_name, property_spec in self.schema_spec[ + "properties" + ].items(): + self.properties[property_name] = resolve(property_spec) + + def match(self, schema: BaseSchema) -> bool: + if ( + not isinstance(schema, ObjectSchema) + or len(self.properties) != len(schema.properties) + or len(self.properties) == 0 + ): + return False + for property_name, property_schema in self.properties.items(): + if property_name not in schema.properties: + # not a match if property is not in schema + return False + elif not property_schema.match(schema.properties[property_name]): + # not a match if schema does not match property schema + return False + return True + + def dump_schema(self) -> dict: + schema = { + "type": "object", + "properties": {}, + } + try: + for property_name, property_schema in self.properties.items(): + schema["properties"][ + property_name + ] = property_schema.dump_schema() + except RecursionError: + print(f"Recursion error in {self.k8s_schema_name}") + exit(1) + return schema + + +class KubernetesStringSchema(KubernetesSchema): + def __init__(self) -> None: + super().__init__() + + def match(self, schema: BaseSchema) -> bool: + if isinstance(schema, StringSchema): + return True + elif isinstance(schema, AnyOfSchema): + return any( + self.match(sub_schema) for sub_schema in schema.possibilities + ) + else: + return isinstance(schema, StringSchema) + + def dump_schema(self) -> dict: + return {"type": "string"} + + +class KubernetesBooleanSchema(KubernetesSchema): + def match(self, schema: BaseSchema) -> bool: + return isinstance(schema, BooleanSchema) + + def dump_schema(self) -> dict: + return {"type": "boolean"} + + +class KubernetesIntegerSchema(KubernetesSchema): + def match(self, schema: BaseSchema) -> bool: + return isinstance(schema, IntegerSchema) + + def dump_schema(self) -> dict: + return {"type": "integer"} + + +class KubernetesFloatSchema(KubernetesSchema): + def match(self, schema: BaseSchema) -> bool: + return isinstance(schema, NumberSchema) + + def dump_schema(self) -> dict: + return {"type": "number"} + + +class KubernetesDictSchema(KubernetesSchema): + def __init__(self, value_cls: KubernetesSchema) -> None: + super().__init__() + self.value: KubernetesSchema = value_cls + + def match(self, schema: BaseSchema) -> bool: + # Dict schema requires additional_properties to be set + # and the value of additional_properties to match the + # additional_properties schema + if isinstance(schema, ObjectSchema): + if schema.additional_properties is None: + return False + elif not self.value.match(schema.additional_properties): + return False + else: + return True + else: + return False + + def dump_schema(self) -> dict: + return { + "type": "object", + "additionalProperties": self.value.dump_schema(), + } + + +class KubernetesListSchema(KubernetesSchema): + def __init__(self, item_cls: KubernetesSchema) -> None: + super().__init__() + self.item: KubernetesSchema = item_cls + + def match(self, schema: BaseSchema) -> bool: + # List schema requires items to be set + # and the value of items to match the + # items schema + if isinstance(schema, ArraySchema): + if schema.item_schema is None: + return False + elif not self.item.match(schema.item_schema): + return False + else: + return True + else: + return False + + def dump_schema(self) -> dict: + return {"type": "array", "items": self.item.dump_schema()} + + +class KubernetesDatetimeSchema(KubernetesSchema): + def match(self, schema: BaseSchema) -> bool: + return isinstance(schema, StringSchema) + + def dump_schema(self) -> dict: + return {"type": "string", "format": "date-time"} + + +class KubernetesOpaqueSchema(KubernetesSchema): + def match(self, schema: BaseSchema) -> bool: + return True + + def dump_schema(self) -> dict: + return {"type": "object"} + + +class ObjectMetaSchema(KubernetesObjectSchema): + def match(self, schema: BaseSchema) -> bool: + if isinstance(schema, OpaqueSchema): + return True + elif isinstance(schema, ObjectSchema): + return super().match(schema) + + +KUBERNETES_SKIP_LIST = [] + + +def fetch_k8s_schema_spec(version: str) -> dict: + """Fetches the Kubernetes schema spec from the Kubernetes repo + + Args: + version (str): the Kubernetes version e.g. "1.29" + + Returns: + dict: the Kubernetes schema spec + """ + r = requests.get( + f"https://raw.githubusercontent.com/kubernetes/kubernetes/release-{version}/api/openapi-spec/swagger.json" + ) + return r.json() + + +class K8sSchemaMatcher: + """Find Kubernetes schemas that match the given schema""" + + def __init__(self, schema_definitions: dict) -> None: + """Initializes the Kubernetes schema matcher with the kubernetes schema + definitions + + Args: + schema_definitions (dict): schema definitions from the Kubernetes schema spec + """ + self._k8s_models = self._generate_k8s_models(schema_definitions) + + @classmethod + def from_version(cls, version: str): + """Factory method that creates a Kubernetes schema matcher from a + Kubernetes version + + Args: + version (str): the Kubernetes version e.g. "1.29" + + Returns: + K8sSchemaMatcher: the Kubernetes schema matcher + """ + schema_definitions = fetch_k8s_schema_spec(version)["definitions"] + return cls(schema_definitions) + + def _generate_k8s_models(self, schema_definitions: dict) -> dict: + """Generates a dictionary of Kubernetes models for schema matching""" + k8s_models = dict() + + def resolve(schema_spec: dict) -> KubernetesSchema: + """Resolves schema type from k8s schema spec""" + + if "$ref" in schema_spec: + type_str = schema_spec["$ref"].split("/")[-1] + try: + return k8s_models[type_str] + except KeyError: + raise KeyError(f"Cannot resolve type {type_str}") + elif schema_spec["type"] == "string": + return KubernetesStringSchema() + elif schema_spec["type"] == "boolean": + return KubernetesBooleanSchema() + elif schema_spec["type"] == "integer": + return KubernetesIntegerSchema() + elif schema_spec["type"] == "number": + return KubernetesFloatSchema() + elif schema_spec["type"] == "object": + return KubernetesOpaqueSchema() + elif schema_spec["type"] == "array": + return KubernetesListSchema(resolve(schema_spec["items"])) + else: + raise KeyError(f"Cannot resolve type {schema_spec}") + + for schema_name, schema_spec in schema_definitions.items(): + if schema_name.startswith("io.k8s.apiextensions-apiserver"): + continue + + if schema_name.endswith("ObjectMeta"): + schema = ObjectMetaSchema(schema_name, schema_spec) + else: + schema = KubernetesObjectSchema(schema_name, schema_spec) + + k8s_models[schema_name] = schema + + for schema in k8s_models.values(): + schema.update(resolve) + + return k8s_models + + def find_matched_schemas(self, schema: BaseSchema) -> BaseSchema: + """Finds all Kubernetes schemas that match the given schema""" + matched_schemas = [] + for kubernetes_schema in self._k8s_models.values(): + if kubernetes_schema.match(schema): + matched_schemas.append((schema, kubernetes_schema)) + return matched_schemas + if isinstance(schema, ObjectSchema): + for sub_schema in schema.properties.values(): + matched_schemas.extend(self.find_matched_schemas(sub_schema)) + elif isinstance(schema, ArraySchema): + matched_schemas.extend( + self.find_matched_schemas(schema.get_item_schema()) + ) + + return matched_schemas + + def dump_k8s_schemas(self) -> dict: + """Dumps all Kubernetes schemas into a dictionary (for debugging)""" + return { + schema_name: schema.dump_schema() + for schema_name, schema in self._k8s_models.items() + } + + +if __name__ == "__main__": + import yaml + import pandas as pd + import os + + # with open("kafka-crd.yml", "r") as f: + with open("./test/integration_tests/test_data/rabbitmq_crd.yaml", "r") as f: + crd = yaml.load(f, Loader=yaml.FullLoader) + + spec_schema = ObjectSchema( + ["root"], crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] + ) + + schema_matcher = K8sSchemaMatcher.from_version("1.29") + matched = schema_matcher.find_matched_schemas(spec_schema) + + for schema, k8s_schema in matched: + print( + f"Matched: '.../{'/'.join(schema.path[-2:])}' -> {k8s_schema.k8s_schema_name}" + ) + + df = pd.DataFrame( + [ + { + "k8s_schema_name": k8s_schema.k8s_schema_name, + "schema_path": "/".join(schema.path), + } + for schema, k8s_schema in matched + ] + ) + + print(df["k8s_schema_name"].value_counts()) + print(f"{len(matched)} schemas matched in total") + + print("Dumping k8s schemas to './schemas' ...") + os.makedirs("schemas", exist_ok=True) + for schema_name, schema in schema_matcher.dump_k8s_schemas().items(): + with open(f"schemas/{schema_name}.json", "w") as f: + yaml.dump(schema, f, indent=2) From ecc604eb9c86045e9ede4a3cb051387b9e6981d4 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Tue, 9 Jan 2024 21:33:42 -0500 Subject: [PATCH 2/9] Apply property-name-based heuristic on ranking matched schema --- acto/input/k8s_schemas.py | 44 +++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py index 6cc1b41592..0bf9b1dccb 100644 --- a/acto/input/k8s_schemas.py +++ b/acto/input/k8s_schemas.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod from typing import Callable +from difflib import SequenceMatcher import requests @@ -258,6 +259,10 @@ def resolve(schema_spec: dict) -> KubernetesSchema: elif schema_spec["type"] == "number": return KubernetesFloatSchema() elif schema_spec["type"] == "object": + if "additionalProperties" in schema_spec: + return KubernetesDictSchema( + resolve(schema_spec["additionalProperties"]) + ) return KubernetesOpaqueSchema() elif schema_spec["type"] == "array": return KubernetesListSchema(resolve(schema_spec["items"])) @@ -280,13 +285,34 @@ def resolve(schema_spec: dict) -> KubernetesSchema: return k8s_models + def _rank_matched_k8s_schemas( + self, + schema: BaseSchema, + matched_schemas: [tuple[BaseSchema, KubernetesSchema]], + ) -> int: + """returns the index of the best matched schemas using heuristic""" + seq_matcher = SequenceMatcher() + seq_matcher.set_seq1( + schema.path[-2] if schema.path[-1] == "ITEM" else schema.path[-1]) + max_ratio = 0 + max_ratio_schema_idx = 0 + for i, (_, matched_schema) in enumerate(matched_schemas): + seq_matcher.set_seq2(matched_schema.k8s_schema_name.split(".")[-1]) + ratio = seq_matcher.ratio() + if ratio > max_ratio: + max_ratio = ratio + max_ratio_schema_idx = i + return max_ratio_schema_idx + def find_matched_schemas(self, schema: BaseSchema) -> BaseSchema: """Finds all Kubernetes schemas that match the given schema""" matched_schemas = [] for kubernetes_schema in self._k8s_models.values(): if kubernetes_schema.match(schema): matched_schemas.append((schema, kubernetes_schema)) - return matched_schemas + if matched_schemas: + idx = self._rank_matched_k8s_schemas(schema, matched_schemas) + return [matched_schemas[idx]] if isinstance(schema, ObjectSchema): for sub_schema in schema.properties.values(): matched_schemas.extend(self.find_matched_schemas(sub_schema)) @@ -322,9 +348,9 @@ def dump_k8s_schemas(self) -> dict: matched = schema_matcher.find_matched_schemas(spec_schema) for schema, k8s_schema in matched: - print( - f"Matched: '.../{'/'.join(schema.path[-2:])}' -> {k8s_schema.k8s_schema_name}" - ) + path_ending = '/'.join(schema.path[-2:]) + schema_name = k8s_schema.k8s_schema_name.split(".")[-1] + print(f"Matched: '.../{path_ending}' -> {schema_name}") df = pd.DataFrame( [ @@ -339,8 +365,8 @@ def dump_k8s_schemas(self) -> dict: print(df["k8s_schema_name"].value_counts()) print(f"{len(matched)} schemas matched in total") - print("Dumping k8s schemas to './schemas' ...") - os.makedirs("schemas", exist_ok=True) - for schema_name, schema in schema_matcher.dump_k8s_schemas().items(): - with open(f"schemas/{schema_name}.json", "w") as f: - yaml.dump(schema, f, indent=2) + # print("Dumping k8s schemas to './schemas' ...") + # os.makedirs("schemas", exist_ok=True) + # for schema_name, schema in schema_matcher.dump_k8s_schemas().items(): + # with open(f"schemas/{schema_name}.json", "w") as f: + # yaml.dump(schema, f, indent=2) From 560f586d2f23eb8b5994ea0dbd9d64eaa9129e72 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Wed, 10 Jan 2024 17:44:36 -0500 Subject: [PATCH 3/9] Improve schema matching heuristic - Observe property names used for each k8s schemas in k8s schema spec and use them to improve ranking of matched schemas --- acto/input/k8s_schemas.py | 73 +++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py index 0bf9b1dccb..c045d41641 100644 --- a/acto/input/k8s_schemas.py +++ b/acto/input/k8s_schemas.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod -from typing import Callable +from collections import defaultdict from difflib import SequenceMatcher +from typing import Callable import requests @@ -222,6 +223,11 @@ def __init__(self, schema_definitions: dict) -> None: schema_definitions (dict): schema definitions from the Kubernetes schema spec """ self._k8s_models = self._generate_k8s_models(schema_definitions) + self._schema_name_to_property_name = ( + self._generate_schema_name_to_property_name_mapping( + schema_definitions + ) + ) @classmethod def from_version(cls, version: str): @@ -237,9 +243,29 @@ def from_version(cls, version: str): schema_definitions = fetch_k8s_schema_spec(version)["definitions"] return cls(schema_definitions) + def _generate_schema_name_to_property_name_mapping( + self, schema_definitions: dict + ) -> dict: + """Builds a dictionary that maps property names to Kubernetes schema name""" + schema_name_to_property_name = defaultdict(set) + for schema_name, schema_spec in schema_definitions.items(): + if schema_name.startswith("io.k8s.apiextensions-apiserver"): + continue + + properties = schema_spec.get("properties", {}) + for property_name, property_schema in properties.items(): + if ref := ( + property_schema.get("$ref") + or property_schema.get("items", {}).get("$ref") + ): + schema_name = ref.split("/")[-1] + schema_name_to_property_name[schema_name].add(property_name) + + return schema_name_to_property_name + def _generate_k8s_models(self, schema_definitions: dict) -> dict: """Generates a dictionary of Kubernetes models for schema matching""" - k8s_models = dict() + k8s_models = {} def resolve(schema_spec: dict) -> KubernetesSchema: """Resolves schema type from k8s schema spec""" @@ -291,17 +317,49 @@ def _rank_matched_k8s_schemas( matched_schemas: [tuple[BaseSchema, KubernetesSchema]], ) -> int: """returns the index of the best matched schemas using heuristic""" + # 1. Give priority to the schemas that have been used with the same + # property name in k8s schema specs + schema_name = ( + schema.path[-2] if schema.path[-1] == "ITEM" else schema.path[-1] + ) + name_matched = [] + for i, (_, k8s_schema) in enumerate(matched_schemas): + observed_schema_names = self._schema_name_to_property_name.get( + k8s_schema.k8s_schema_name, set() + ) + for observed_schema_name in observed_schema_names: + if schema_name in observed_schema_name: + name_matched.append(i) + + # 2. Use the edit distance between the last salient segment of the + # schema path and the last salient segment of the k8s schema name + # to rank the matched schemas seq_matcher = SequenceMatcher() - seq_matcher.set_seq1( - schema.path[-2] if schema.path[-1] == "ITEM" else schema.path[-1]) + # set seq1 to the last salient segment of the schema path + schema_name = "/".join( + schema.path[-3:-1] + if schema.path[-1] == "ITEM" + else schema.path[-2:] + ) + seq_matcher.set_seq1(schema_name) max_ratio = 0 max_ratio_schema_idx = 0 for i, (_, matched_schema) in enumerate(matched_schemas): + if name_matched and i not in name_matched: + continue seq_matcher.set_seq2(matched_schema.k8s_schema_name.split(".")[-1]) ratio = seq_matcher.ratio() + if len(matched_schemas) > 1: + print(ratio, matched_schema.k8s_schema_name.split(".")[-1]) if ratio > max_ratio: max_ratio = ratio max_ratio_schema_idx = i + if len(matched_schemas) > 1: + print( + schema.path, + "choose", + matched_schemas[max_ratio_schema_idx][1].k8s_schema_name, + ) return max_ratio_schema_idx def find_matched_schemas(self, schema: BaseSchema) -> BaseSchema: @@ -332,10 +390,11 @@ def dump_k8s_schemas(self) -> dict: if __name__ == "__main__": - import yaml - import pandas as pd import os + import pandas as pd + import yaml + # with open("kafka-crd.yml", "r") as f: with open("./test/integration_tests/test_data/rabbitmq_crd.yaml", "r") as f: crd = yaml.load(f, Loader=yaml.FullLoader) @@ -348,7 +407,7 @@ def dump_k8s_schemas(self) -> dict: matched = schema_matcher.find_matched_schemas(spec_schema) for schema, k8s_schema in matched: - path_ending = '/'.join(schema.path[-2:]) + path_ending = "/".join(schema.path[-2:]) schema_name = k8s_schema.k8s_schema_name.split(".")[-1] print(f"Matched: '.../{path_ending}' -> {schema_name}") From 4f5523b32b274217f2944a0193bf40c7cff3b4a5 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Wed, 10 Jan 2024 20:35:33 -0500 Subject: [PATCH 4/9] Fix code style and add documentation --- acto/input/k8s_schemas.py | 88 +++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py index c045d41641..20ad3956d7 100644 --- a/acto/input/k8s_schemas.py +++ b/acto/input/k8s_schemas.py @@ -1,3 +1,12 @@ +"""A module that contains the Kubernetes schema matcher + +This module contains the Kubernetes schema matcher that matches acto schemas +to Kubernetes schemas. It is used for generating Kubernetes CRD schemas from +acto schemas. +""" +# pylint: disable=redefined-outer-name + +import sys from abc import ABC, abstractmethod from collections import defaultdict from difflib import SequenceMatcher @@ -24,15 +33,15 @@ class KubernetesSchema(ABC): @abstractmethod def match(self, schema: BaseSchema) -> bool: """Determines if the schema matches the Kubernetes schema""" - ... @abstractmethod def dump_schema(self) -> dict: """Dumps the Kubernetes schema into a dictionary (for debugging)""" - ... class KubernetesObjectSchema(KubernetesSchema): + """Class for Kubernetes object schema matching""" + def __init__(self, schema_name, schema_spec) -> None: self.k8s_schema_name: str = schema_name self.schema_spec = schema_spec @@ -47,7 +56,7 @@ def update(self, resolve: Callable[[dict], "KubernetesSchema"]) -> None: ].items(): self.properties[property_name] = resolve(property_spec) - def match(self, schema: BaseSchema) -> bool: + def match(self, schema) -> bool: if ( not isinstance(schema, ObjectSchema) or len(self.properties) != len(schema.properties) @@ -75,15 +84,14 @@ def dump_schema(self) -> dict: ] = property_schema.dump_schema() except RecursionError: print(f"Recursion error in {self.k8s_schema_name}") - exit(1) + sys.exit(1) return schema class KubernetesStringSchema(KubernetesSchema): - def __init__(self) -> None: - super().__init__() + """Class for Kubernetes string schema matching""" - def match(self, schema: BaseSchema) -> bool: + def match(self, schema) -> bool: if isinstance(schema, StringSchema): return True elif isinstance(schema, AnyOfSchema): @@ -98,7 +106,9 @@ def dump_schema(self) -> dict: class KubernetesBooleanSchema(KubernetesSchema): - def match(self, schema: BaseSchema) -> bool: + """Class for Kubernetes boolean schema matching""" + + def match(self, schema) -> bool: return isinstance(schema, BooleanSchema) def dump_schema(self) -> dict: @@ -106,7 +116,9 @@ def dump_schema(self) -> dict: class KubernetesIntegerSchema(KubernetesSchema): - def match(self, schema: BaseSchema) -> bool: + """Class for Kubernetes integer schema matching""" + + def match(self, schema) -> bool: return isinstance(schema, IntegerSchema) def dump_schema(self) -> dict: @@ -114,7 +126,9 @@ def dump_schema(self) -> dict: class KubernetesFloatSchema(KubernetesSchema): - def match(self, schema: BaseSchema) -> bool: + """Class for Kubernetes float schema matching""" + + def match(self, schema) -> bool: return isinstance(schema, NumberSchema) def dump_schema(self) -> dict: @@ -122,11 +136,13 @@ def dump_schema(self) -> dict: class KubernetesDictSchema(KubernetesSchema): + """Class for Kubernetes dict schema matching""" + def __init__(self, value_cls: KubernetesSchema) -> None: super().__init__() self.value: KubernetesSchema = value_cls - def match(self, schema: BaseSchema) -> bool: + def match(self, schema) -> bool: # Dict schema requires additional_properties to be set # and the value of additional_properties to match the # additional_properties schema @@ -148,11 +164,13 @@ def dump_schema(self) -> dict: class KubernetesListSchema(KubernetesSchema): + """Class for Kubernetes list schema matching""" + def __init__(self, item_cls: KubernetesSchema) -> None: super().__init__() self.item: KubernetesSchema = item_cls - def match(self, schema: BaseSchema) -> bool: + def match(self, schema) -> bool: # List schema requires items to be set # and the value of items to match the # items schema @@ -171,7 +189,9 @@ def dump_schema(self) -> dict: class KubernetesDatetimeSchema(KubernetesSchema): - def match(self, schema: BaseSchema) -> bool: + """Class for Kubernetes datetime schema matching""" + + def match(self, schema) -> bool: return isinstance(schema, StringSchema) def dump_schema(self) -> dict: @@ -179,7 +199,9 @@ def dump_schema(self) -> dict: class KubernetesOpaqueSchema(KubernetesSchema): - def match(self, schema: BaseSchema) -> bool: + """Class for Kubernetes opaque schema matching""" + + def match(self, schema) -> bool: return True def dump_schema(self) -> dict: @@ -187,11 +209,14 @@ def dump_schema(self) -> dict: class ObjectMetaSchema(KubernetesObjectSchema): - def match(self, schema: BaseSchema) -> bool: + """Class for Kubernetes ObjectMeta schema matching""" + + def match(self, schema) -> bool: if isinstance(schema, OpaqueSchema): return True - elif isinstance(schema, ObjectSchema): + if isinstance(schema, ObjectSchema): return super().match(schema) + return False KUBERNETES_SKIP_LIST = [] @@ -206,10 +231,12 @@ def fetch_k8s_schema_spec(version: str) -> dict: Returns: dict: the Kubernetes schema spec """ - r = requests.get( - f"https://raw.githubusercontent.com/kubernetes/kubernetes/release-{version}/api/openapi-spec/swagger.json" + # pylint: disable=line-too-long + resp = requests.get( + f"https://raw.githubusercontent.com/kubernetes/kubernetes/release-{version}/api/openapi-spec/swagger.json", + timeout=5, ) - return r.json() + return resp.json() class K8sSchemaMatcher: @@ -274,8 +301,8 @@ def resolve(schema_spec: dict) -> KubernetesSchema: type_str = schema_spec["$ref"].split("/")[-1] try: return k8s_models[type_str] - except KeyError: - raise KeyError(f"Cannot resolve type {type_str}") + except KeyError as exc: + raise KeyError(f"Cannot resolve type {type_str}") from exc elif schema_spec["type"] == "string": return KubernetesStringSchema() elif schema_spec["type"] == "boolean": @@ -349,17 +376,9 @@ def _rank_matched_k8s_schemas( continue seq_matcher.set_seq2(matched_schema.k8s_schema_name.split(".")[-1]) ratio = seq_matcher.ratio() - if len(matched_schemas) > 1: - print(ratio, matched_schema.k8s_schema_name.split(".")[-1]) if ratio > max_ratio: max_ratio = ratio max_ratio_schema_idx = i - if len(matched_schemas) > 1: - print( - schema.path, - "choose", - matched_schemas[max_ratio_schema_idx][1].k8s_schema_name, - ) return max_ratio_schema_idx def find_matched_schemas(self, schema: BaseSchema) -> BaseSchema: @@ -390,13 +409,17 @@ def dump_k8s_schemas(self) -> dict: if __name__ == "__main__": - import os + # import os import pandas as pd import yaml - # with open("kafka-crd.yml", "r") as f: - with open("./test/integration_tests/test_data/rabbitmq_crd.yaml", "r") as f: + with open( + # "./test/integration_tests/test_data/kafka_crd.yaml", + "./test/integration_tests/test_data/rabbitmq_crd.yaml", + "r", + encoding="utf-8", + ) as f: crd = yaml.load(f, Loader=yaml.FullLoader) spec_schema = ObjectSchema( @@ -407,6 +430,7 @@ def dump_k8s_schemas(self) -> dict: matched = schema_matcher.find_matched_schemas(spec_schema) for schema, k8s_schema in matched: + # pylint: disable-next=invalid-name path_ending = "/".join(schema.path[-2:]) schema_name = k8s_schema.k8s_schema_name.split(".")[-1] print(f"Matched: '.../{path_ending}' -> {schema_name}") From 640a2fe6af953dd15827eed35e4ab849fd37e412 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Thu, 11 Jan 2024 14:00:06 -0500 Subject: [PATCH 5/9] Add test cases for K8sSchemaMatcher - Added kafka_crd to test_data/ - Added test case generation code - Partially fixed pylint warnings in test code --- acto/input/k8s_schemas.py | 13 +- .../test_data/kafka_crd.yaml | 7928 +++++++++++++++++ test/integration_tests/test_known_schemas.py | 349 +- 3 files changed, 8234 insertions(+), 56 deletions(-) create mode 100644 test/integration_tests/test_data/kafka_crd.yaml diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py index 20ad3956d7..b5d021189f 100644 --- a/acto/input/k8s_schemas.py +++ b/acto/input/k8s_schemas.py @@ -389,7 +389,8 @@ def find_matched_schemas(self, schema: BaseSchema) -> BaseSchema: matched_schemas.append((schema, kubernetes_schema)) if matched_schemas: idx = self._rank_matched_k8s_schemas(schema, matched_schemas) - return [matched_schemas[idx]] + matched_schemas = [matched_schemas[idx]] + return matched_schemas if isinstance(schema, ObjectSchema): for sub_schema in schema.properties.values(): matched_schemas.extend(self.find_matched_schemas(sub_schema)) @@ -415,6 +416,7 @@ def dump_k8s_schemas(self) -> dict: import yaml with open( + # "./test/integration_tests/test_data/cassop_crd.yaml", # "./test/integration_tests/test_data/kafka_crd.yaml", "./test/integration_tests/test_data/rabbitmq_crd.yaml", "r", @@ -435,6 +437,13 @@ def dump_k8s_schemas(self) -> dict: schema_name = k8s_schema.k8s_schema_name.split(".")[-1] print(f"Matched: '.../{path_ending}' -> {schema_name}") + # # generate integration test code + # for schema, k8s_schema in matched: + # # pylint: disable-next=invalid-name + # path_ending = "/".join(schema.path[-3:]) + # schema_name = '.'.join(k8s_schema.k8s_schema_name.split(".")[-2:]) + # print(f'self.assert_exists("{path_ending}", "{schema_name}", matches)') + df = pd.DataFrame( [ { @@ -445,7 +454,7 @@ def dump_k8s_schemas(self) -> dict: ] ) - print(df["k8s_schema_name"].value_counts()) + print(df["k8s_schema_name"].value_counts().to_string()) print(f"{len(matched)} schemas matched in total") # print("Dumping k8s schemas to './schemas' ...") diff --git a/test/integration_tests/test_data/kafka_crd.yaml b/test/integration_tests/test_data/kafka_crd.yaml new file mode 100644 index 0000000000..24b543b3b2 --- /dev/null +++ b/test/integration_tests/test_data/kafka_crd.yaml @@ -0,0 +1,7928 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kafkas.kafka.strimzi.io + labels: + app: strimzi + strimzi.io/crd-install: 'true' +spec: + group: kafka.strimzi.io + names: + kind: Kafka + listKind: KafkaList + singular: kafka + plural: kafkas + shortNames: + - k + categories: + - strimzi + scope: Namespaced + conversion: + strategy: None + versions: + - name: v1beta2 + served: true + storage: true + subresources: + status: {} + additionalPrinterColumns: + - name: Desired Kafka replicas + description: The desired number of Kafka replicas in the cluster + jsonPath: .spec.kafka.replicas + type: integer + - name: Desired ZK replicas + description: The desired number of ZooKeeper replicas in the cluster + jsonPath: .spec.zookeeper.replicas + type: integer + - name: Ready + description: The state of the custom resource + jsonPath: '.status.conditions[?(@.type=="Ready")].status' + type: string + - name: Warnings + description: Warnings related to the custom resource + jsonPath: '.status.conditions[?(@.type=="Warning")].status' + type: string + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + kafka: + type: object + properties: + version: + type: string + description: >- + The kafka broker version. Defaults to + {DefaultKafkaVersion}. Consult the user documentation to + understand the process required to upgrade or downgrade + the version. + replicas: + type: integer + minimum: 1 + description: The number of pods in the cluster. + image: + type: string + description: >- + The docker image for the pods. The default value depends + on the configured `Kafka.spec.kafka.version`. + listeners: + type: array + minItems: 1 + items: + type: object + properties: + name: + type: string + pattern: '^[a-z0-9]{1,11}$' + description: >- + Name of the listener. The name will be used to + identify the listener and the related Kubernetes + objects. The name has to be unique within given a + Kafka cluster. The name can consist of lowercase + characters and numbers and be up to 11 characters + long. + port: + type: integer + minimum: 9092 + description: >- + Port number used by the listener inside Kafka. The + port number has to be unique within a given Kafka + cluster. Allowed port numbers are 9092 and higher + with the exception of ports 9404 and 9999, which + are already used for Prometheus and JMX. Depending + on the listener type, the port number might not be + the same as the port number that connects Kafka + clients. + type: + type: string + enum: + - internal + - route + - loadbalancer + - nodeport + - ingress + - cluster-ip + description: > + Type of the listener. Currently the supported + types are `internal`, `route`, `loadbalancer`, + `nodeport` and `ingress`. + + + * `internal` type exposes Kafka internally only + within the Kubernetes cluster. + + * `route` type uses OpenShift Routes to expose + Kafka. + + * `loadbalancer` type uses LoadBalancer type + services to expose Kafka. + + * `nodeport` type uses NodePort type services to + expose Kafka. + + * `ingress` type uses Kubernetes Nginx Ingress to + expose Kafka with TLS passthrough. + + * `cluster-ip` type uses a per-broker `ClusterIP` + service. + tls: + type: boolean + description: >- + Enables TLS encryption on the listener. This is a + required property. + authentication: + type: object + properties: + accessTokenIsJwt: + type: boolean + description: >- + Configure whether the access token is treated + as JWT. This must be set to `false` if the + authorization server returns opaque tokens. + Defaults to `true`. + checkAccessTokenType: + type: boolean + description: >- + Configure whether the access token type check + is performed or not. This should be set to + `false` if the authorization server does not + include 'typ' claim in JWT token. Defaults to + `true`. + checkAudience: + type: boolean + description: >- + Enable or disable audience checking. Audience + checks identify the recipients of tokens. If + audience checking is enabled, the OAuth Client + ID also has to be configured using the + `clientId` property. The Kafka broker will + reject tokens that do not have its `clientId` + in their `aud` (audience) claim.Default value + is `false`. + checkIssuer: + type: boolean + description: >- + Enable or disable issuer checking. By default + issuer is checked using the value configured + by `validIssuerUri`. Default value is `true`. + clientAudience: + type: string + description: >- + The audience to use when making requests to + the authorization server's token endpoint. + Used for inter-broker authentication and for + configuring OAuth 2.0 over PLAIN using the + `clientId` and `secret` method. + clientId: + type: string + description: >- + OAuth Client ID which the Kafka broker can use + to authenticate against the authorization + server and use the introspect endpoint URI. + clientScope: + type: string + description: >- + The scope to use when making requests to the + authorization server's token endpoint. Used + for inter-broker authentication and for + configuring OAuth 2.0 over PLAIN using the + `clientId` and `secret` method. + clientSecret: + type: object + properties: + key: + type: string + description: >- + The key under which the secret value is + stored in the Kubernetes Secret. + secretName: + type: string + description: >- + The name of the Kubernetes Secret + containing the secret value. + required: + - key + - secretName + description: >- + Link to Kubernetes Secret containing the OAuth + client secret which the Kafka broker can use + to authenticate against the authorization + server and use the introspect endpoint URI. + connectTimeoutSeconds: + type: integer + description: >- + The connect timeout in seconds when connecting + to authorization server. If not set, the + effective connect timeout is 60 seconds. + customClaimCheck: + type: string + description: >- + JsonPath filter query to be applied to the JWT + token or to the response of the introspection + endpoint for additional token validation. Not + set by default. + disableTlsHostnameVerification: + type: boolean + description: >- + Enable or disable TLS hostname verification. + Default value is `false`. + enableECDSA: + type: boolean + description: >- + Enable or disable ECDSA support by installing + BouncyCastle crypto provider. ECDSA support is + always enabled. The BouncyCastle libraries are + no longer packaged with Strimzi. Value is + ignored. + enableMetrics: + type: boolean + description: >- + Enable or disable OAuth metrics. Default value + is `false`. + enableOauthBearer: + type: boolean + description: >- + Enable or disable OAuth authentication over + SASL_OAUTHBEARER. Default value is `true`. + enablePlain: + type: boolean + description: >- + Enable or disable OAuth authentication over + SASL_PLAIN. There is no re-authentication + support when this mechanism is used. Default + value is `false`. + failFast: + type: boolean + description: >- + Enable or disable termination of Kafka broker + processes due to potentially recoverable + runtime errors during startup. Default value + is `true`. + fallbackUserNameClaim: + type: string + description: >- + The fallback username claim to be used for the + user id if the claim specified by + `userNameClaim` is not present. This is useful + when `client_credentials` authentication only + results in the client id being provided in + another claim. It only takes effect if + `userNameClaim` is set. + fallbackUserNamePrefix: + type: string + description: >- + The prefix to use with the value of + `fallbackUserNameClaim` to construct the user + id. This only takes effect if + `fallbackUserNameClaim` is true, and the value + is present for the claim. Mapping usernames + and client ids into the same user id space is + useful in preventing name collisions. + groupsClaim: + type: string + description: >- + JsonPath query used to extract groups for the + user during authentication. Extracted groups + can be used by a custom authorizer. By default + no groups are extracted. + groupsClaimDelimiter: + type: string + description: >- + A delimiter used to parse groups when they are + extracted as a single String value rather than + a JSON array. Default value is ',' (comma). + httpRetries: + type: integer + description: >- + The maximum number of retries to attempt if an + initial HTTP request fails. If not set, the + default is to not attempt any retries. + httpRetryPauseMs: + type: integer + description: >- + The pause to take before retrying a failed + HTTP request. If not set, the default is to + not pause at all but to immediately repeat a + request. + includeAcceptHeader: + type: boolean + description: >- + Whether the Accept header should be set in + requests to the authorization servers. The + default value is `true`. + introspectionEndpointUri: + type: string + description: >- + URI of the token introspection endpoint which + can be used to validate opaque non-JWT tokens. + jwksEndpointUri: + type: string + description: >- + URI of the JWKS certificate endpoint, which + can be used for local JWT validation. + jwksExpirySeconds: + type: integer + minimum: 1 + description: >- + Configures how often are the JWKS certificates + considered valid. The expiry interval has to + be at least 60 seconds longer then the refresh + interval specified in `jwksRefreshSeconds`. + Defaults to 360 seconds. + jwksIgnoreKeyUse: + type: boolean + description: >- + Flag to ignore the 'use' attribute of `key` + declarations in a JWKS endpoint response. + Default value is `false`. + jwksMinRefreshPauseSeconds: + type: integer + minimum: 0 + description: >- + The minimum pause between two consecutive + refreshes. When an unknown signing key is + encountered the refresh is scheduled + immediately, but will always wait for this + minimum pause. Defaults to 1 second. + jwksRefreshSeconds: + type: integer + minimum: 1 + description: >- + Configures how often are the JWKS certificates + refreshed. The refresh interval has to be at + least 60 seconds shorter then the expiry + interval specified in `jwksExpirySeconds`. + Defaults to 300 seconds. + listenerConfig: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Configuration to be used for a specific + listener. All values are prefixed with + listener.name.__. + maxSecondsWithoutReauthentication: + type: integer + description: >- + Maximum number of seconds the authenticated + session remains valid without + re-authentication. This enables Apache Kafka + re-authentication feature, and causes sessions + to expire when the access token expires. If + the access token expires before max time or if + max time is reached, the client has to + re-authenticate, otherwise the server will + drop the connection. Not set by default - the + authenticated session does not expire when the + access token expires. This option only applies + to SASL_OAUTHBEARER authentication mechanism + (when `enableOauthBearer` is `true`). + readTimeoutSeconds: + type: integer + description: >- + The read timeout in seconds when connecting to + authorization server. If not set, the + effective read timeout is 60 seconds. + sasl: + type: boolean + description: Enable or disable SASL on this listener. + secrets: + type: array + items: + type: object + properties: + key: + type: string + description: >- + The key under which the secret value is + stored in the Kubernetes Secret. + secretName: + type: string + description: >- + The name of the Kubernetes Secret + containing the secret value. + required: + - key + - secretName + description: >- + Secrets to be mounted to + /opt/kafka/custom-authn-secrets/custom-listener-_-_/__. + tlsTrustedCertificates: + type: array + items: + type: object + properties: + certificate: + type: string + description: >- + The name of the file certificate in the + Secret. + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + required: + - certificate + - secretName + description: >- + Trusted certificates for TLS connection to the + OAuth server. + tokenEndpointUri: + type: string + description: >- + URI of the Token Endpoint to use with + SASL_PLAIN mechanism when the client + authenticates with `clientId` and a `secret`. + If set, the client can authenticate over + SASL_PLAIN by either setting `username` to + `clientId`, and setting `password` to client + `secret`, or by setting `username` to account + username, and `password` to access token + prefixed with `$accessToken:`. If this option + is not set, the `password` is always + interpreted as an access token (without a + prefix), and `username` as the account + username (a so called 'no-client-credentials' + mode). + type: + type: string + enum: + - tls + - scram-sha-512 + - oauth + - custom + description: >- + Authentication type. `oauth` type uses SASL + OAUTHBEARER Authentication. `scram-sha-512` + type uses SASL SCRAM-SHA-512 Authentication. + `tls` type uses TLS Client Authentication. + `tls` type is supported only on TLS + listeners.`custom` type allows for any + authentication type to be used. + userInfoEndpointUri: + type: string + description: >- + URI of the User Info Endpoint to use as a + fallback to obtaining the user id when the + Introspection Endpoint does not return + information that can be used for the user id. + userNameClaim: + type: string + description: >- + Name of the claim from the JWT authentication + token, Introspection Endpoint response or User + Info Endpoint response which will be used to + extract the user id. Defaults to `sub`. + validIssuerUri: + type: string + description: >- + URI of the token issuer used for + authentication. + validTokenType: + type: string + description: >- + Valid value for the `token_type` attribute + returned by the Introspection Endpoint. No + default value, and not checked by default. + required: + - type + description: Authentication configuration for this listener. + configuration: + type: object + properties: + brokerCertChainAndKey: + type: object + properties: + certificate: + type: string + description: >- + The name of the file certificate in the + Secret. + key: + type: string + description: The name of the private key in the Secret. + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + required: + - certificate + - key + - secretName + description: >- + Reference to the `Secret` which holds the + certificate and private key pair which will be + used for this listener. The certificate can + optionally contain the whole chain. This field + can be used only with listeners with enabled + TLS encryption. + externalTrafficPolicy: + type: string + enum: + - Local + - Cluster + description: >- + Specifies whether the service routes external + traffic to node-local or cluster-wide + endpoints. `Cluster` may cause a second hop to + another node and obscures the client source + IP. `Local` avoids a second hop for + LoadBalancer and Nodeport type services and + preserves the client source IP (when supported + by the infrastructure). If unspecified, + Kubernetes will use `Cluster` as the + default.This field can be used only with + `loadbalancer` or `nodeport` type listener. + loadBalancerSourceRanges: + type: array + items: + type: string + description: >- + A list of CIDR ranges (for example + `10.0.0.0/8` or `130.211.204.1/32`) from which + clients can connect to load balancer type + listeners. If supported by the platform, + traffic through the loadbalancer is restricted + to the specified CIDR ranges. This field is + applicable only for loadbalancer type services + and is ignored if the cloud provider does not + support the feature. This field can be used + only with `loadbalancer` type listener. + bootstrap: + type: object + properties: + alternativeNames: + type: array + items: + type: string + description: >- + Additional alternative names for the + bootstrap service. The alternative names + will be added to the list of subject + alternative names of the TLS certificates. + host: + type: string + description: >- + The bootstrap host. This field will be + used in the Ingress resource or in the + Route resource to specify the desired + hostname. This field can be used only with + `route` (optional) or `ingress` (required) + type listeners. + nodePort: + type: integer + description: >- + Node port for the bootstrap service. This + field can be used only with `nodeport` + type listener. + loadBalancerIP: + type: string + description: >- + The loadbalancer is requested with the IP + address specified in this field. This + feature depends on whether the underlying + cloud provider supports specifying the + `loadBalancerIP` when a load balancer is + created. This field is ignored if the + cloud provider does not support the + feature.This field can be used only with + `loadbalancer` type listener. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations that will be added to the + `Ingress`, `Route`, or `Service` resource. + You can use this field to configure DNS + providers such as External DNS. This field + can be used only with `loadbalancer`, + `nodeport`, `route`, or `ingress` type + listeners. + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Labels that will be added to the + `Ingress`, `Route`, or `Service` resource. + This field can be used only with + `loadbalancer`, `nodeport`, `route`, or + `ingress` type listeners. + description: Bootstrap configuration. + brokers: + type: array + items: + type: object + properties: + broker: + type: integer + description: >- + ID of the kafka broker (broker + identifier). Broker IDs start from 0 and + correspond to the number of broker + replicas. + advertisedHost: + type: string + description: >- + The host name used in the brokers' + `advertised.listeners`. + advertisedPort: + type: integer + description: >- + The port number used in the brokers' + `advertised.listeners`. + host: + type: string + description: >- + The broker host. This field will be used + in the Ingress resource or in the Route + resource to specify the desired + hostname. This field can be used only + with `route` (optional) or `ingress` + (required) type listeners. + nodePort: + type: integer + description: >- + Node port for the per-broker service. + This field can be used only with + `nodeport` type listener. + loadBalancerIP: + type: string + description: >- + The loadbalancer is requested with the + IP address specified in this field. This + feature depends on whether the + underlying cloud provider supports + specifying the `loadBalancerIP` when a + load balancer is created. This field is + ignored if the cloud provider does not + support the feature.This field can be + used only with `loadbalancer` type + listener. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations that will be added to the + `Ingress` or `Service` resource. You can + use this field to configure DNS + providers such as External DNS. This + field can be used only with + `loadbalancer`, `nodeport`, or `ingress` + type listeners. + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Labels that will be added to the + `Ingress`, `Route`, or `Service` + resource. This field can be used only + with `loadbalancer`, `nodeport`, + `route`, or `ingress` type listeners. + required: + - broker + description: Per-broker configurations. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two + IP families on dual-stack configured clusters. + If unspecified, Kubernetes will choose the + default value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the + default value based on the `ipFamilyPolicy` + setting. + createBootstrapService: + type: boolean + description: >- + Whether to create the bootstrap service or + not. The bootstrap service is created by + default (if not specified differently). This + field can be used with the `loadBalancer` type + listener. + class: + type: string + description: >- + Configures a specific class for `Ingress` and + `LoadBalancer` that defines which controller + will be used. This field can only be used with + `ingress` and `loadbalancer` type listeners. + If not specified, the default controller is + used. For an `ingress` listener, set the + `ingressClassName` property in the `Ingress` + resources. For a `loadbalancer` listener, set + the `loadBalancerClass` property in the + `Service` resources. + finalizers: + type: array + items: + type: string + description: >- + A list of finalizers which will be configured + for the `LoadBalancer` type Services created + for this listener. If supported by the + platform, the finalizer + `service.kubernetes.io/load-balancer-cleanup` + to make sure that the external load balancer + is deleted together with the service.For more + information, see + https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#garbage-collecting-load-balancers. + This field can be used only with + `loadbalancer` type listeners. + maxConnectionCreationRate: + type: integer + description: >- + The maximum connection creation rate we allow + in this listener at any time. New connections + will be throttled if the limit is reached. + maxConnections: + type: integer + description: >- + The maximum number of connections we allow for + this listener in the broker at any time. New + connections are blocked if the limit is + reached. + preferredNodePortAddressType: + type: string + enum: + - ExternalIP + - ExternalDNS + - InternalIP + - InternalDNS + - Hostname + description: >- + Defines which address type should be used as + the node address. Available types are: + `ExternalDNS`, `ExternalIP`, `InternalDNS`, + `InternalIP` and `Hostname`. By default, the + addresses will be used in the following order + (the first one found will be used): + + + * `ExternalDNS` + + * `ExternalIP` + + * `InternalDNS` + + * `InternalIP` + + * `Hostname` + + + This field is used to select the preferred + address type, which is checked first. If no + address is found for this address type, the + other types are checked in the default order. + This field can only be used with `nodeport` + type listener. + useServiceDnsDomain: + type: boolean + description: >- + Configures whether the Kubernetes service DNS + domain should be used or not. If set to + `true`, the generated addresses will contain + the service DNS domain suffix (by default + `.cluster.local`, can be configured using + environment variable + `KUBERNETES_SERVICE_DNS_DOMAIN`). Defaults to + `false`.This field can be used only with + `internal` and `cluster-ip` type listeners. + description: Additional listener configuration. + networkPolicyPeers: + type: array + items: + type: object + properties: + ipBlock: + type: object + properties: + cidr: + type: string + except: + type: array + items: + type: string + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + podSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + List of peers which should be able to connect to + this listener. Peers in this list are combined + using a logical OR operation. If this field is + empty or missing, all connections will be allowed + for this listener. If this field is present and + contains at least one item, the listener only + allows the traffic which matches at least one item + in this list. + required: + - name + - port + - type + - tls + description: Configures listeners of Kafka brokers. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Kafka broker config properties with the following + prefixes cannot be set: listeners, advertised., broker., + listener., host.name, port, inter.broker.listener.name, + sasl., ssl., security., password., log.dir, + zookeeper.connect, zookeeper.set.acl, zookeeper.ssl, + zookeeper.clientCnxnSocket, authorizer., super.user, + cruise.control.metrics.topic, + cruise.control.metrics.reporter.bootstrap.servers,node.id, + process.roles, controller., metadata.log.dir (with the + exception of: zookeeper.connection.timeout.ms, + sasl.server.max.receive.size,ssl.cipher.suites, + ssl.protocol, ssl.enabled.protocols, + ssl.secure.random.implementation,cruise.control.metrics.topic.num.partitions, + cruise.control.metrics.topic.replication.factor, + cruise.control.metrics.topic.retention.ms,cruise.control.metrics.topic.auto.create.retries, + cruise.control.metrics.topic.auto.create.timeout.ms,cruise.control.metrics.topic.min.insync.replicas,controller.quorum.election.backoff.max.ms, + controller.quorum.election.timeout.ms, + controller.quorum.fetch.timeout.ms). + storage: + type: object + properties: + class: + type: string + description: >- + The storage class to use for dynamic volume + allocation. + deleteClaim: + type: boolean + description: >- + Specifies if the persistent volume claim has to be + deleted when the cluster is un-deployed. + id: + type: integer + minimum: 0 + description: >- + Storage identification number. It is mandatory only + for storage volumes defined in a storage of type + 'jbod'. + overrides: + type: array + items: + type: object + properties: + class: + type: string + description: >- + The storage class to use for dynamic volume + allocation for this broker. + broker: + type: integer + description: Id of the kafka broker (broker identifier). + description: >- + Overrides for individual brokers. The `overrides` + field allows to specify a different configuration + for different brokers. + selector: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Specifies a specific persistent volume to use. It + contains key:value pairs representing labels for + selecting such a volume. + size: + type: string + description: >- + When type=persistent-claim, defines the size of the + persistent volume claim (i.e 1Gi). Mandatory when + type=persistent-claim. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + When type=ephemeral, defines the total amount of + local storage required for this EmptyDir volume (for + example 1Gi). + type: + type: string + enum: + - ephemeral + - persistent-claim + - jbod + description: >- + Storage type, must be either 'ephemeral', + 'persistent-claim', or 'jbod'. + volumes: + type: array + items: + type: object + properties: + class: + type: string + description: >- + The storage class to use for dynamic volume + allocation. + deleteClaim: + type: boolean + description: >- + Specifies if the persistent volume claim has + to be deleted when the cluster is un-deployed. + id: + type: integer + minimum: 0 + description: >- + Storage identification number. It is mandatory + only for storage volumes defined in a storage + of type 'jbod'. + overrides: + type: array + items: + type: object + properties: + class: + type: string + description: >- + The storage class to use for dynamic + volume allocation for this broker. + broker: + type: integer + description: >- + Id of the kafka broker (broker + identifier). + description: >- + Overrides for individual brokers. The + `overrides` field allows to specify a + different configuration for different brokers. + selector: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Specifies a specific persistent volume to use. + It contains key:value pairs representing + labels for selecting such a volume. + size: + type: string + description: >- + When type=persistent-claim, defines the size + of the persistent volume claim (i.e 1Gi). + Mandatory when type=persistent-claim. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + When type=ephemeral, defines the total amount + of local storage required for this EmptyDir + volume (for example 1Gi). + type: + type: string + enum: + - ephemeral + - persistent-claim + description: >- + Storage type, must be either 'ephemeral' or + 'persistent-claim'. + required: + - type + description: >- + List of volumes as Storage objects representing the + JBOD disks array. + required: + - type + description: Storage configuration (disk). Cannot be updated. + authorization: + type: object + properties: + allowOnError: + type: boolean + description: >- + Defines whether a Kafka client should be allowed or + denied by default when the authorizer fails to query + the Open Policy Agent, for example, when it is + temporarily unavailable). Defaults to `false` - all + actions will be denied. + authorizerClass: + type: string + description: >- + Authorization implementation class, which must be + available in classpath. + clientId: + type: string + description: >- + OAuth Client ID which the Kafka client can use to + authenticate against the OAuth server and use the + token endpoint URI. + connectTimeoutSeconds: + type: integer + minimum: 1 + description: >- + The connect timeout in seconds when connecting to + authorization server. If not set, the effective + connect timeout is 60 seconds. + delegateToKafkaAcls: + type: boolean + description: >- + Whether authorization decision should be delegated + to the 'Simple' authorizer if DENIED by Keycloak + Authorization Services policies. Default value is + `false`. + disableTlsHostnameVerification: + type: boolean + description: >- + Enable or disable TLS hostname verification. Default + value is `false`. + enableMetrics: + type: boolean + description: >- + Enable or disable OAuth metrics. The default value + is `false`. + expireAfterMs: + type: integer + description: >- + The expiration of the records kept in the local + cache to avoid querying the Open Policy Agent for + every request. Defines how often the cached + authorization decisions are reloaded from the Open + Policy Agent server. In milliseconds. Defaults to + `3600000`. + grantsAlwaysLatest: + type: boolean + description: >- + Controls whether the latest grants are fetched for a + new session. When enabled, grants are retrieved from + Keycloak and cached for the user. The default value + is `false`. + grantsGcPeriodSeconds: + type: integer + minimum: 1 + description: >- + The time, in seconds, between consecutive runs of a + job that cleans stale grants from the cache. The + default value is 300. + grantsMaxIdleTimeSeconds: + type: integer + minimum: 1 + description: >- + The time, in seconds, after which an idle grant can + be evicted from the cache. The default value is 300. + grantsRefreshPeriodSeconds: + type: integer + minimum: 0 + description: >- + The time between two consecutive grants refresh runs + in seconds. The default value is 60. + grantsRefreshPoolSize: + type: integer + minimum: 1 + description: >- + The number of threads to use to refresh grants for + active sessions. The more threads, the more + parallelism, so the sooner the job completes. + However, using more threads places a heavier load on + the authorization server. The default value is 5. + httpRetries: + type: integer + minimum: 0 + description: >- + The maximum number of retries to attempt if an + initial HTTP request fails. If not set, the default + is to not attempt any retries. + includeAcceptHeader: + type: boolean + description: >- + Whether the Accept header should be set in requests + to the authorization servers. The default value is + `true`. + initialCacheCapacity: + type: integer + description: >- + Initial capacity of the local cache used by the + authorizer to avoid querying the Open Policy Agent + for every request Defaults to `5000`. + maximumCacheSize: + type: integer + description: >- + Maximum capacity of the local cache used by the + authorizer to avoid querying the Open Policy Agent + for every request. Defaults to `50000`. + readTimeoutSeconds: + type: integer + minimum: 1 + description: >- + The read timeout in seconds when connecting to + authorization server. If not set, the effective read + timeout is 60 seconds. + superUsers: + type: array + items: + type: string + description: >- + List of super users, which are user principals with + unlimited access rights. + supportsAdminApi: + type: boolean + description: >- + Indicates whether the custom authorizer supports the + APIs for managing ACLs using the Kafka Admin API. + Defaults to `false`. + tlsTrustedCertificates: + type: array + items: + type: object + properties: + certificate: + type: string + description: >- + The name of the file certificate in the + Secret. + secretName: + type: string + description: >- + The name of the Secret containing the + certificate. + required: + - certificate + - secretName + description: >- + Trusted certificates for TLS connection to the OAuth + server. + tokenEndpointUri: + type: string + description: Authorization server token endpoint URI. + type: + type: string + enum: + - simple + - opa + - keycloak + - custom + description: >- + Authorization type. Currently, the supported types + are `simple`, `keycloak`, `opa` and `custom`. + `simple` authorization type uses Kafka's built-in + authorizer for authorization. `keycloak` + authorization type uses Keycloak Authorization + Services for authorization. `opa` authorization type + uses Open Policy Agent based authorization.`custom` + authorization type uses user-provided implementation + for authorization. + url: + type: string + example: 'http://opa:8181/v1/data/kafka/authz/allow' + description: >- + The URL used to connect to the Open Policy Agent + server. The URL has to include the policy which will + be queried by the authorizer. This option is + required. + required: + - type + description: Authorization configuration for Kafka brokers. + rack: + type: object + properties: + topologyKey: + type: string + example: topology.kubernetes.io/zone + description: >- + A key that matches labels assigned to the Kubernetes + cluster nodes. The value of the label is used to set + a broker's `broker.rack` config, and the + `client.rack` config for Kafka Connect or + MirrorMaker 2. + required: + - topologyKey + description: Configuration of the `broker.rack` broker config. + brokerRackInitImage: + type: string + description: >- + The image of the init container used for initializing + the `broker.rack`. + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod readiness checking. + jvmOptions: + type: object + properties: + '-XX': + x-kubernetes-preserve-unknown-fields: true + type: object + description: A map of -XX options to the JVM. + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for pods. + jmxOptions: + type: object + properties: + authentication: + type: object + properties: + type: + type: string + enum: + - password + description: >- + Authentication type. Currently the only + supported types are `password`.`password` type + creates a username and protected port with no + TLS. + required: + - type + description: >- + Authentication configuration for connecting to the + JMX port. + description: JMX Options for Kafka brokers. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + description: >- + Metrics type. Only 'jmxPrometheusExporter' supported + currently. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. For details of the + structure of this configuration, see the + {JMXExporter}. + required: + - type + - valueFrom + description: Metrics configuration. + logging: + type: object + properties: + loggers: + x-kubernetes-preserve-unknown-fields: true + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration for Kafka. + template: + type: object + properties: + statefulset: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + podManagementPolicy: + type: string + enum: + - OrderedReady + - Parallel + description: >- + PodManagementPolicy which will be used for this + StatefulSet. Valid values are `Parallel` and + `OrderedReady`. Defaults to `Parallel`. + description: Template for Kafka `StatefulSet`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. For more information about + priority classes, see {K8sPriorityClass}. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount (for example `1Gi`) of + local storage required for temporary EmptyDir + volume (`/tmp`). Default value is `5Mi`. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + description: Template for Kafka `Pods`. + bootstrapService: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka bootstrap `Service`. + brokersService: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Kafka broker `Service`. + externalBootstrapService: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka external bootstrap `Service`. + perPodService: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Services` used for + access from outside of Kubernetes. + externalBootstrapRoute: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka external bootstrap `Route`. + perPodRoute: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Routes` used for access + from outside of OpenShift. + externalBootstrapIngress: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka external bootstrap `Ingress`. + perPodIngress: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Kafka per-pod `Ingress` used for access + from outside of Kubernetes. + persistentVolumeClaim: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for all Kafka `PersistentVolumeClaims`. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is + allowed when the `maxUnavailable` number of pods + or fewer are unavailable after the eviction. + Setting this value to 0 prevents all voluntary + evictions, so the pods must be evicted manually. + Defaults to 1. + description: Template for Kafka `PodDisruptionBudget`. + kafkaContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for the Kafka broker container. + initContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for the Kafka init container. + clusterCaCert: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Secret with Kafka Cluster certificate + public key. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Kafka service account. + jmxSecret: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Secret of the Kafka Cluster JMX + authentication. + clusterRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Kafka ClusterRoleBinding. + podSet: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka `StrimziPodSet` resource. + description: >- + Template for Kafka cluster resources. The template + allows users to specify how the Kubernetes resources are + generated. + required: + - replicas + - listeners + - storage + description: Configuration of the Kafka cluster. + zookeeper: + type: object + properties: + replicas: + type: integer + minimum: 1 + description: The number of pods in the cluster. + image: + type: string + description: The docker image for the pods. + storage: + type: object + properties: + class: + type: string + description: >- + The storage class to use for dynamic volume + allocation. + deleteClaim: + type: boolean + description: >- + Specifies if the persistent volume claim has to be + deleted when the cluster is un-deployed. + id: + type: integer + minimum: 0 + description: >- + Storage identification number. It is mandatory only + for storage volumes defined in a storage of type + 'jbod'. + overrides: + type: array + items: + type: object + properties: + class: + type: string + description: >- + The storage class to use for dynamic volume + allocation for this broker. + broker: + type: integer + description: Id of the kafka broker (broker identifier). + description: >- + Overrides for individual brokers. The `overrides` + field allows to specify a different configuration + for different brokers. + selector: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Specifies a specific persistent volume to use. It + contains key:value pairs representing labels for + selecting such a volume. + size: + type: string + description: >- + When type=persistent-claim, defines the size of the + persistent volume claim (i.e 1Gi). Mandatory when + type=persistent-claim. + sizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + When type=ephemeral, defines the total amount of + local storage required for this EmptyDir volume (for + example 1Gi). + type: + type: string + enum: + - ephemeral + - persistent-claim + description: >- + Storage type, must be either 'ephemeral' or + 'persistent-claim'. + required: + - type + description: Storage configuration (disk). Cannot be updated. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The ZooKeeper broker config. Properties with the + following prefixes cannot be set: server., dataDir, + dataLogDir, clientPort, authProvider, quorum.auth, + requireClientAuthScheme, snapshot.trust.empty, + standaloneEnabled, reconfigEnabled, + 4lw.commands.whitelist, secureClientPort, ssl., + serverCnxnFactory, sslQuorum (with the exception of: + ssl.protocol, ssl.quorum.protocol, ssl.enabledProtocols, + ssl.quorum.enabledProtocols, ssl.ciphersuites, + ssl.quorum.ciphersuites, ssl.hostnameVerification, + ssl.quorum.hostnameVerification). + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod readiness checking. + jvmOptions: + type: object + properties: + '-XX': + x-kubernetes-preserve-unknown-fields: true + type: object + description: A map of -XX options to the JVM. + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for pods. + jmxOptions: + type: object + properties: + authentication: + type: object + properties: + type: + type: string + enum: + - password + description: >- + Authentication type. Currently the only + supported types are `password`.`password` type + creates a username and protected port with no + TLS. + required: + - type + description: >- + Authentication configuration for connecting to the + JMX port. + description: JMX Options for Zookeeper nodes. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + description: >- + Metrics type. Only 'jmxPrometheusExporter' supported + currently. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. For details of the + structure of this configuration, see the + {JMXExporter}. + required: + - type + - valueFrom + description: Metrics configuration. + logging: + type: object + properties: + loggers: + x-kubernetes-preserve-unknown-fields: true + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration for ZooKeeper. + template: + type: object + properties: + statefulset: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + podManagementPolicy: + type: string + enum: + - OrderedReady + - Parallel + description: >- + PodManagementPolicy which will be used for this + StatefulSet. Valid values are `Parallel` and + `OrderedReady`. Defaults to `Parallel`. + description: Template for ZooKeeper `StatefulSet`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. For more information about + priority classes, see {K8sPriorityClass}. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount (for example `1Gi`) of + local storage required for temporary EmptyDir + volume (`/tmp`). Default value is `5Mi`. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + description: Template for ZooKeeper `Pods`. + clientService: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for ZooKeeper client `Service`. + nodesService: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for ZooKeeper nodes `Service`. + persistentVolumeClaim: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for all ZooKeeper `PersistentVolumeClaims`. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is + allowed when the `maxUnavailable` number of pods + or fewer are unavailable after the eviction. + Setting this value to 0 prevents all voluntary + evictions, so the pods must be evicted manually. + Defaults to 1. + description: Template for ZooKeeper `PodDisruptionBudget`. + zookeeperContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for the ZooKeeper container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the ZooKeeper service account. + jmxSecret: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: >- + Template for Secret of the Zookeeper Cluster JMX + authentication. + podSet: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for ZooKeeper `StrimziPodSet` resource. + description: >- + Template for ZooKeeper cluster resources. The template + allows users to specify how the Kubernetes resources are + generated. + required: + - replicas + - storage + description: Configuration of the ZooKeeper cluster. + entityOperator: + type: object + properties: + topicOperator: + type: object + properties: + watchedNamespace: + type: string + description: The namespace the Topic Operator should watch. + image: + type: string + description: The image to use for the Topic Operator. + reconciliationIntervalSeconds: + type: integer + minimum: 0 + description: Interval between periodic reconciliations. + zookeeperSessionTimeoutSeconds: + type: integer + minimum: 0 + description: Timeout for the ZooKeeper session. + startupProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod startup checking. + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod readiness checking. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + topicMetadataMaxAttempts: + type: integer + minimum: 0 + description: The number of attempts at getting topic metadata. + logging: + type: object + properties: + loggers: + x-kubernetes-preserve-unknown-fields: true + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: >- + Logging type, must be either 'inline' or + 'external'. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap + containing the configuration. + description: >- + `ConfigMap` entry where the logging + configuration is stored. + required: + - type + description: Logging configuration. + jvmOptions: + type: object + properties: + '-XX': + x-kubernetes-preserve-unknown-fields: true + type: object + description: A map of -XX options to the JVM. + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging + is enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will + be passed using the `-D` option to the JVM. + description: JVM Options for pods. + description: Configuration of the Topic Operator. + userOperator: + type: object + properties: + watchedNamespace: + type: string + description: The namespace the User Operator should watch. + image: + type: string + description: The image to use for the User Operator. + reconciliationIntervalSeconds: + type: integer + minimum: 0 + description: Interval between periodic reconciliations. + zookeeperSessionTimeoutSeconds: + type: integer + minimum: 0 + description: Timeout for the ZooKeeper session. + secretPrefix: + type: string + description: >- + The prefix that will be added to the KafkaUser name + to be used as the Secret name. + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod liveness checking. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod readiness checking. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + logging: + type: object + properties: + loggers: + x-kubernetes-preserve-unknown-fields: true + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: >- + Logging type, must be either 'inline' or + 'external'. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap + containing the configuration. + description: >- + `ConfigMap` entry where the logging + configuration is stored. + required: + - type + description: Logging configuration. + jvmOptions: + type: object + properties: + '-XX': + x-kubernetes-preserve-unknown-fields: true + type: object + description: A map of -XX options to the JVM. + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging + is enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will + be passed using the `-D` option to the JVM. + description: JVM Options for pods. + description: Configuration of the User Operator. + tlsSidecar: + type: object + properties: + image: + type: string + description: The docker image for the container. + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod liveness checking. + logLevel: + type: string + enum: + - emerg + - alert + - crit + - err + - warning + - notice + - info + - debug + description: >- + The log level for the TLS sidecar. Default value is + `notice`. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod readiness checking. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + description: TLS sidecar configuration. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for Entity Operator `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. For more information about + priority classes, see {K8sPriorityClass}. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount (for example `1Gi`) of + local storage required for temporary EmptyDir + volume (`/tmp`). Default value is `5Mi`. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + description: Template for Entity Operator `Pods`. + topicOperatorContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for the Entity Topic Operator container. + userOperatorContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for the Entity User Operator container. + tlsSidecarContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: >- + Template for the Entity Operator TLS sidecar + container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Operator service account. + entityOperatorRole: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Operator Role. + topicOperatorRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Topic Operator RoleBinding. + userOperatorRoleBinding: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Entity Topic Operator RoleBinding. + description: >- + Template for Entity Operator resources. The template + allows users to specify how a `Deployment` and `Pod` is + generated. + description: Configuration of the Entity Operator. + clusterCa: + type: object + properties: + generateCertificateAuthority: + type: boolean + description: >- + If true then Certificate Authority certificates will be + generated automatically. Otherwise the user will need to + provide a Secret with the CA certificate. Default is + true. + generateSecretOwnerReference: + type: boolean + description: >- + If `true`, the Cluster and Client CA Secrets are + configured with the `ownerReference` set to the `Kafka` + resource. If the `Kafka` resource is deleted when + `true`, the CA Secrets are also deleted. If `false`, the + `ownerReference` is disabled. If the `Kafka` resource is + deleted when `false`, the CA Secrets are retained and + available for reuse. Default is `true`. + validityDays: + type: integer + minimum: 1 + description: >- + The number of days generated certificates should be + valid for. The default is 365. + renewalDays: + type: integer + minimum: 1 + description: >- + The number of days in the certificate renewal period. + This is the number of days before the a certificate + expires during which renewal actions may be performed. + When `generateCertificateAuthority` is true, this will + cause the generation of a new certificate. When + `generateCertificateAuthority` is true, this will cause + extra logging at WARN level about the pending + certificate expiry. Default is 30. + certificateExpirationPolicy: + type: string + enum: + - renew-certificate + - replace-key + description: >- + How should CA certificate expiration be handled when + `generateCertificateAuthority=true`. The default is for + a new CA certificate to be generated reusing the + existing private key. + description: Configuration of the cluster certificate authority. + clientsCa: + type: object + properties: + generateCertificateAuthority: + type: boolean + description: >- + If true then Certificate Authority certificates will be + generated automatically. Otherwise the user will need to + provide a Secret with the CA certificate. Default is + true. + generateSecretOwnerReference: + type: boolean + description: >- + If `true`, the Cluster and Client CA Secrets are + configured with the `ownerReference` set to the `Kafka` + resource. If the `Kafka` resource is deleted when + `true`, the CA Secrets are also deleted. If `false`, the + `ownerReference` is disabled. If the `Kafka` resource is + deleted when `false`, the CA Secrets are retained and + available for reuse. Default is `true`. + validityDays: + type: integer + minimum: 1 + description: >- + The number of days generated certificates should be + valid for. The default is 365. + renewalDays: + type: integer + minimum: 1 + description: >- + The number of days in the certificate renewal period. + This is the number of days before the a certificate + expires during which renewal actions may be performed. + When `generateCertificateAuthority` is true, this will + cause the generation of a new certificate. When + `generateCertificateAuthority` is true, this will cause + extra logging at WARN level about the pending + certificate expiry. Default is 30. + certificateExpirationPolicy: + type: string + enum: + - renew-certificate + - replace-key + description: >- + How should CA certificate expiration be handled when + `generateCertificateAuthority=true`. The default is for + a new CA certificate to be generated reusing the + existing private key. + description: Configuration of the clients certificate authority. + cruiseControl: + type: object + properties: + image: + type: string + description: The docker image for the pods. + tlsSidecar: + type: object + properties: + image: + type: string + description: The docker image for the container. + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod liveness checking. + logLevel: + type: string + enum: + - emerg + - alert + - crit + - err + - warning + - notice + - info + - debug + description: >- + The log level for the TLS sidecar. Default value is + `notice`. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is + first checked. Default to 15 seconds. Minimum + value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to + be considered successful after having failed. + Defaults to 1. Must be 1 for liveness. Minimum + value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. + Default to 5 seconds. Minimum value is 1. + description: Pod readiness checking. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + description: TLS sidecar configuration. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + CPU and memory resources to reserve for the Cruise + Control container. + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod liveness checking for the Cruise Control container. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod readiness checking for the Cruise Control container. + jvmOptions: + type: object + properties: + '-XX': + x-kubernetes-preserve-unknown-fields: true + type: object + description: A map of -XX options to the JVM. + '-Xms': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xms option to to the JVM.' + '-Xmx': + type: string + pattern: '^[0-9]+[mMgG]?$' + description: '-Xmx option to to the JVM.' + gcLoggingEnabled: + type: boolean + description: >- + Specifies whether the Garbage Collection logging is + enabled. The default is false. + javaSystemProperties: + type: array + items: + type: object + properties: + name: + type: string + description: The system property name. + value: + type: string + description: The system property value. + description: >- + A map of additional system properties which will be + passed using the `-D` option to the JVM. + description: JVM Options for the Cruise Control container. + logging: + type: object + properties: + loggers: + x-kubernetes-preserve-unknown-fields: true + type: object + description: A Map from logger name to logger level. + type: + type: string + enum: + - inline + - external + description: 'Logging type, must be either ''inline'' or ''external''.' + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + `ConfigMap` entry where the logging configuration is + stored. + required: + - type + description: Logging configuration (Log4j 2) for Cruise Control. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for Cruise Control `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. For more information about + priority classes, see {K8sPriorityClass}. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount (for example `1Gi`) of + local storage required for temporary EmptyDir + volume (`/tmp`). Default value is `5Mi`. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + description: Template for Cruise Control `Pods`. + apiService: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + ipFamilyPolicy: + type: string + enum: + - SingleStack + - PreferDualStack + - RequireDualStack + description: >- + Specifies the IP Family Policy used by the + service. Available options are `SingleStack`, + `PreferDualStack` and `RequireDualStack`. + `SingleStack` is for a single IP family. + `PreferDualStack` is for two IP families on + dual-stack configured clusters or a single IP + family on single-stack clusters. + `RequireDualStack` fails unless there are two IP + families on dual-stack configured clusters. If + unspecified, Kubernetes will choose the default + value based on the service type. + ipFamilies: + type: array + items: + type: string + enum: + - IPv4 + - IPv6 + description: >- + Specifies the IP Families used by the service. + Available options are `IPv4` and `IPv6`. If + unspecified, Kubernetes will choose the default + value based on the `ipFamilyPolicy` setting. + description: Template for Cruise Control API `Service`. + podDisruptionBudget: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: >- + Metadata to apply to the + `PodDisruptionBudgetTemplate` resource. + maxUnavailable: + type: integer + minimum: 0 + description: >- + Maximum number of unavailable pods to allow + automatic Pod eviction. A Pod eviction is + allowed when the `maxUnavailable` number of pods + or fewer are unavailable after the eviction. + Setting this value to 0 prevents all voluntary + evictions, so the pods must be evicted manually. + Defaults to 1. + description: Template for Cruise Control `PodDisruptionBudget`. + cruiseControlContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for the Cruise Control container. + tlsSidecarContainer: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: >- + Template for the Cruise Control TLS sidecar + container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Cruise Control service account. + description: >- + Template to specify how Cruise Control resources, + `Deployments` and `Pods`, are generated. + brokerCapacity: + type: object + properties: + disk: + type: string + pattern: '^[0-9]+([.][0-9]*)?([KMGTPE]i?|e[0-9]+)?$' + description: >- + Broker capacity for disk in bytes. Use a number + value with either standard Kubernetes byte units (K, + M, G, or T), their bibyte (power of two) equivalents + (Ki, Mi, Gi, or Ti), or a byte value with or without + E notation. For example, 100000M, 100000Mi, + 104857600000, or 1e+11. + cpuUtilization: + type: integer + minimum: 0 + maximum: 100 + description: >- + Broker capacity for CPU resource utilization as a + percentage (0 - 100). + cpu: + type: string + pattern: '^[0-9]+([.][0-9]{0,3}|[m]?)$' + description: >- + Broker capacity for CPU resource in cores or + millicores. For example, 1, 1.500, 1500m. For more + information on valid CPU resource units see + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu. + inboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for inbound network throughput in + bytes per second. Use an integer value with standard + Kubernetes byte units (K, M, G) or their bibyte + (power of two) equivalents (Ki, Mi, Gi) per second. + For example, 10000KiB/s. + outboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for outbound network throughput in + bytes per second. Use an integer value with standard + Kubernetes byte units (K, M, G) or their bibyte + (power of two) equivalents (Ki, Mi, Gi) per second. + For example, 10000KiB/s. + overrides: + type: array + items: + type: object + properties: + brokers: + type: array + items: + type: integer + description: List of Kafka brokers (broker identifiers). + cpu: + type: string + pattern: '^[0-9]+([.][0-9]{0,3}|[m]?)$' + description: >- + Broker capacity for CPU resource in cores or + millicores. For example, 1, 1.500, 1500m. For + more information on valid CPU resource units + see + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu. + inboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for inbound network throughput + in bytes per second. Use an integer value with + standard Kubernetes byte units (K, M, G) or + their bibyte (power of two) equivalents (Ki, + Mi, Gi) per second. For example, 10000KiB/s. + outboundNetwork: + type: string + pattern: '^[0-9]+([KMG]i?)?B/s$' + description: >- + Broker capacity for outbound network + throughput in bytes per second. Use an integer + value with standard Kubernetes byte units (K, + M, G) or their bibyte (power of two) + equivalents (Ki, Mi, Gi) per second. For + example, 10000KiB/s. + required: + - brokers + description: >- + Overrides for individual brokers. The `overrides` + property lets you specify a different capacity + configuration for different brokers. + description: The Cruise Control `brokerCapacity` configuration. + config: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + The Cruise Control configuration. For a full list of + configuration options refer to + https://github.com/linkedin/cruise-control/wiki/Configurations. + Note that properties with the following prefixes cannot + be set: bootstrap.servers, client.id, zookeeper., + network., security., + failed.brokers.zk.path,webserver.http., + webserver.api.urlprefix, webserver.session.path, + webserver.accesslog., two.step., + request.reason.required,metric.reporter.sampler.bootstrap.servers, + capacity.config.file, self.healing., ssl., + kafka.broker.failure.detection.enable, + topic.config.provider.class (with the exception of: + ssl.cipher.suites, ssl.protocol, ssl.enabled.protocols, + webserver.http.cors.enabled, webserver.http.cors.origin, + webserver.http.cors.exposeheaders, + webserver.security.enable, webserver.ssl.enable). + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + description: >- + Metrics type. Only 'jmxPrometheusExporter' supported + currently. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: >- + Reference to the key in the ConfigMap containing + the configuration. + description: >- + ConfigMap entry where the Prometheus JMX Exporter + configuration is stored. For details of the + structure of this configuration, see the + {JMXExporter}. + required: + - type + - valueFrom + description: Metrics configuration. + description: >- + Configuration for Cruise Control deployment. Deploys a + Cruise Control instance when specified. + jmxTrans: + type: object + properties: + image: + type: string + description: The image to use for the JmxTrans. + outputDefinitions: + type: array + items: + type: object + properties: + outputType: + type: string + description: >- + Template for setting the format of the data that + will be pushed.For more information see + https://github.com/jmxtrans/jmxtrans/wiki/OutputWriters[JmxTrans + OutputWriters]. + host: + type: string + description: >- + The DNS/hostname of the remote host that the data + is pushed to. + port: + type: integer + description: >- + The port of the remote host that the data is + pushed to. + flushDelayInSeconds: + type: integer + description: >- + How many seconds the JmxTrans waits before pushing + a new set of data out. + typeNames: + type: array + items: + type: string + description: >- + Template for filtering data to be included in + response to a wildcard query. For more information + see + https://github.com/jmxtrans/jmxtrans/wiki/Queries[JmxTrans + queries]. + name: + type: string + description: >- + Template for setting the name of the output + definition. This is used to identify where to send + the results of queries should be sent. + required: + - outputType + - name + description: >- + Defines the output hosts that will be referenced later + on. For more information on these properties see, + xref:type-JmxTransOutputDefinitionTemplate-reference[`JmxTransOutputDefinitionTemplate` + schema reference]. + logLevel: + type: string + description: >- + Sets the logging level of the JmxTrans deployment.For + more information see, + https://github.com/jmxtrans/jmxtrans-agent/wiki/Troubleshooting[JmxTrans + Logging Level]. + kafkaQueries: + type: array + items: + type: object + properties: + targetMBean: + type: string + description: >- + If using wildcards instead of a specific MBean + then the data is gathered from multiple MBeans. + Otherwise if specifying an MBean then data is + gathered from that specified MBean. + attributes: + type: array + items: + type: string + description: >- + Determine which attributes of the targeted MBean + should be included. + outputs: + type: array + items: + type: string + description: >- + List of the names of output definitions specified + in the spec.kafka.jmxTrans.outputDefinitions that + have defined where JMX metrics are pushed to, and + in which data format. + required: + - targetMBean + - attributes + - outputs + description: >- + Queries to send to the Kafka brokers to define what data + should be read from each broker. For more information on + these properties see, + xref:type-JmxTransQueryTemplate-reference[`JmxTransQueryTemplate` + schema reference]. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for JmxTrans `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. For more information about + priority classes, see {K8sPriorityClass}. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount (for example `1Gi`) of + local storage required for temporary EmptyDir + volume (`/tmp`). Default value is `5Mi`. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + description: Template for JmxTrans `Pods`. + container: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for JmxTrans container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the JmxTrans service account. + description: Template for JmxTrans resources. + required: + - outputDefinitions + - kafkaQueries + description: >- + As of Strimzi 0.35.0, JMXTrans is not supported anymore and + this option is ignored. + kafkaExporter: + type: object + properties: + image: + type: string + description: The docker image for the pods. + groupRegex: + type: string + description: >- + Regular expression to specify which consumer groups to + collect. Default value is `.*`. + topicRegex: + type: string + description: >- + Regular expression to specify which topics to collect. + Default value is `.*`. + groupExcludeRegex: + type: string + description: >- + Regular expression to specify which consumer groups to + exclude. + topicExcludeRegex: + type: string + description: Regular expression to specify which topics to exclude. + resources: + type: object + properties: + claims: + type: array + items: + type: object + properties: + name: + type: string + limits: + x-kubernetes-preserve-unknown-fields: true + type: object + requests: + x-kubernetes-preserve-unknown-fields: true + type: object + description: CPU and memory resources to reserve. + logging: + type: string + description: >- + Only log messages with the given severity or above. + Valid levels: [`info`, `debug`, `trace`]. Default log + level is `info`. + enableSaramaLogging: + type: boolean + description: >- + Enable Sarama logging, a Go client library used by the + Kafka Exporter. + template: + type: object + properties: + deployment: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + deploymentStrategy: + type: string + enum: + - RollingUpdate + - Recreate + description: >- + Pod replacement strategy for deployment + configuration changes. Valid values are + `RollingUpdate` and `Recreate`. Defaults to + `RollingUpdate`. + description: Template for Kafka Exporter `Deployment`. + pod: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + imagePullSecrets: + type: array + items: + type: object + properties: + name: + type: string + description: >- + List of references to secrets in the same + namespace to use for pulling any of the images + used by this Pod. When the + `STRIMZI_IMAGE_PULL_SECRETS` environment + variable in Cluster Operator and the + `imagePullSecrets` option are specified, only + the `imagePullSecrets` variable is used and the + `STRIMZI_IMAGE_PULL_SECRETS` variable is + ignored. + securityContext: + type: object + properties: + fsGroup: + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + supplementalGroups: + type: array + items: + type: integer + sysctls: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: >- + Configures pod-level security attributes and + common container settings. + terminationGracePeriodSeconds: + type: integer + minimum: 0 + description: >- + The grace period is the duration in seconds + after the processes running in the pod are sent + a termination signal, and the time when the + processes are forcibly halted with a kill + signal. Set this value to longer than the + expected cleanup time for your process. Value + must be a non-negative integer. A zero value + indicates delete immediately. You might need to + increase the grace period for very large Kafka + clusters, so that the Kafka brokers have enough + time to transfer their work to another broker + before they are terminated. Defaults to 30 + seconds. + affinity: + type: object + properties: + nodeAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + preference: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: object + properties: + nodeSelectorTerms: + type: array + items: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + podAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + podAntiAffinity: + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + podAffinityTerm: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + weight: + type: integer + requiredDuringSchedulingIgnoredDuringExecution: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaceSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + namespaces: + type: array + items: + type: string + topologyKey: + type: string + description: The pod's affinity rules. + tolerations: + type: array + items: + type: object + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + type: integer + value: + type: string + description: The pod's tolerations. + priorityClassName: + type: string + description: >- + The name of the priority class used to assign + priority to the pods. For more information about + priority classes, see {K8sPriorityClass}. + schedulerName: + type: string + description: >- + The name of the scheduler used to dispatch this + `Pod`. If not specified, the default scheduler + will be used. + hostAliases: + type: array + items: + type: object + properties: + hostnames: + type: array + items: + type: string + ip: + type: string + description: >- + The pod's HostAliases. HostAliases is an + optional list of hosts and IPs that will be + injected into the Pod's hosts file if specified. + tmpDirSizeLimit: + type: string + pattern: '^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$' + description: >- + Defines the total amount (for example `1Gi`) of + local storage required for temporary EmptyDir + volume (`/tmp`). Default value is `5Mi`. + enableServiceLinks: + type: boolean + description: >- + Indicates whether information about services + should be injected into Pod's environment + variables. + topologySpreadConstraints: + type: array + items: + type: object + properties: + labelSelector: + type: object + properties: + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string + matchLabels: + x-kubernetes-preserve-unknown-fields: true + type: object + matchLabelKeys: + type: array + items: + type: string + maxSkew: + type: integer + minDomains: + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + description: The pod's topology spread constraints. + description: Template for Kafka Exporter `Pods`. + service: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for Kafka Exporter `Service`. + container: + type: object + properties: + env: + type: array + items: + type: object + properties: + name: + type: string + description: The environment variable key. + value: + type: string + description: The environment variable value. + description: >- + Environment variables which should be applied to + the container. + securityContext: + type: object + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + type: object + properties: + add: + type: array + items: + type: string + drop: + type: array + items: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + type: integer + runAsNonRoot: + type: boolean + runAsUser: + type: integer + seLinuxOptions: + type: object + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + seccompProfile: + type: object + properties: + localhostProfile: + type: string + type: + type: string + windowsOptions: + type: object + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + description: Security context for the container. + description: Template for the Kafka Exporter container. + serviceAccount: + type: object + properties: + metadata: + type: object + properties: + labels: + x-kubernetes-preserve-unknown-fields: true + type: object + description: Labels added to the Kubernetes resource. + annotations: + x-kubernetes-preserve-unknown-fields: true + type: object + description: >- + Annotations added to the Kubernetes + resource. + description: Metadata applied to the resource. + description: Template for the Kafka Exporter service account. + description: Customization of deployment templates and pods. + livenessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod liveness check. + readinessProbe: + type: object + properties: + failureThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive failures for the probe to be + considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + initialDelaySeconds: + type: integer + minimum: 0 + description: >- + The initial delay before first the health is first + checked. Default to 15 seconds. Minimum value is 0. + periodSeconds: + type: integer + minimum: 1 + description: >- + How often (in seconds) to perform the probe. Default + to 10 seconds. Minimum value is 1. + successThreshold: + type: integer + minimum: 1 + description: >- + Minimum consecutive successes for the probe to be + considered successful after having failed. Defaults + to 1. Must be 1 for liveness. Minimum value is 1. + timeoutSeconds: + type: integer + minimum: 1 + description: >- + The timeout for each attempted health check. Default + to 5 seconds. Minimum value is 1. + description: Pod readiness check. + description: >- + Configuration of the Kafka Exporter. Kafka Exporter can + provide additional metrics, for example lag of consumer + group at topic/partition. + maintenanceTimeWindows: + type: array + items: + type: string + description: >- + A list of time windows for maintenance tasks (that is, + certificates renewal). Each time window is defined by a cron + expression. + required: + - kafka + - zookeeper + description: >- + The specification of the Kafka and ZooKeeper clusters, and Topic + Operator. + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + description: >- + The unique identifier of a condition, used to + distinguish between other conditions in the resource. + status: + type: string + description: >- + The status of the condition, either True, False or + Unknown. + lastTransitionTime: + type: string + description: >- + Last time the condition of a type changed from one + status to another. The required format is + 'yyyy-MM-ddTHH:mm:ssZ', in the UTC time zone. + reason: + type: string + description: >- + The reason for the condition's last transition (a + single word in CamelCase). + message: + type: string + description: >- + Human-readable message indicating details about the + condition's last transition. + description: List of status conditions. + observedGeneration: + type: integer + description: >- + The generation of the CRD that was last reconciled by the + operator. + listeners: + type: array + items: + type: object + properties: + type: + type: string + description: The name of the listener. + name: + type: string + description: The name of the listener. + addresses: + type: array + items: + type: object + properties: + host: + type: string + description: >- + The DNS name or IP address of the Kafka + bootstrap service. + port: + type: integer + description: The port of the Kafka bootstrap service. + description: A list of the addresses for this listener. + bootstrapServers: + type: string + description: >- + A comma-separated list of `host:port` pairs for + connecting to the Kafka cluster using this listener. + certificates: + type: array + items: + type: string + description: >- + A list of TLS certificates which can be used to verify + the identity of the server when connecting to the + given listener. Set only for `tls` and `external` + listeners. + description: Addresses of the internal and external listeners. + kafkaNodePools: + type: array + items: + type: object + properties: + name: + type: string + description: >- + The name of the KafkaNodePool used by this Kafka + resource. + description: List of the KafkaNodePools used by this Kafka cluster. + clusterId: + type: string + description: Kafka cluster Id. + operatorLastSuccessfulVersion: + type: string + description: >- + The version of the Strimzi Cluster Operator which performed + the last successful reconciliation. + kafkaVersion: + type: string + description: The version of Kafka currently deployed in the cluster. + description: >- + The status of the Kafka and ZooKeeper clusters, and Topic + Operator. diff --git a/test/integration_tests/test_known_schemas.py b/test/integration_tests/test_known_schemas.py index 7ec3ab0ad2..a829204cbc 100644 --- a/test/integration_tests/test_known_schemas.py +++ b/test/integration_tests/test_known_schemas.py @@ -1,3 +1,5 @@ +# pylint: disable=missing-docstring, line-too-long, redefine-outer-name + import os import pathlib import unittest @@ -5,149 +7,388 @@ import yaml from acto.input.get_matched_schemas import field_matched +from acto.input.k8s_schemas import K8sSchemaMatcher, KubernetesSchema from acto.input.known_schemas import * from acto.input.valuegenerator import extract_schema_with_value_generator from acto.schema import extract_schema test_dir = pathlib.Path(__file__).parent.resolve() -test_data_dir = os.path.join(test_dir, 'test_data') +test_data_dir = os.path.join(test_dir, "test_data") class TestSchema(unittest.TestCase): + """This class tests the schema matching code for various CRDs.""" + + @classmethod + def setUpClass(cls): + cls.schema_matcher = K8sSchemaMatcher.from_version("1.29") + + def assert_exists( + self, + suffix: str, + schema_name: str, + matches: [tuple[BaseSchema, KubernetesSchema]], + ): + applied = 0 + for schema, k8s_schema in matches: + schema_path = "/".join(schema.path) + if schema_path.endswith(suffix): + self.assertTrue( + k8s_schema.k8s_schema_name.endswith(schema_name), + f"Schema name mismatch! Path={schema_path} Expected={schema_name} Actual={k8s_schema.k8s_schema_name}", + ) + applied += 1 + if applied == 0: + self.fail(f"Schema path suffix {schema_name} not found") + + def test_rabbitmq_crd(self): + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), + "r", + encoding="utf-8", + ) as operator_yaml: + crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) + spec_schema = extract_schema( + [], crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] + ) + matches = self.schema_matcher.find_matched_schemas(spec_schema) + self.assert_exists("labelSelector", "v1.LabelSelector", matches) + self.assert_exists("exec", "v1.ExecAction", matches) + self.assert_exists("httpGet/httpHeaders/ITEM", "v1.HTTPHeader", matches) + self.assert_exists("fieldRef", "v1.ObjectFieldSelector", matches) + self.assert_exists("seLinuxOptions", "v1.SELinuxOptions", matches) + self.assert_exists("seccompProfile", "v1.SeccompProfile", matches) + self.assert_exists("volumeMounts/ITEM", "v1.VolumeMount", matches) + self.assert_exists("configMapKeyRef", "v1.ConfigMapKeySelector", matches) + self.assert_exists("secretKeyRef", "v1.SecretKeySelector", matches) + self.assert_exists("envFrom/ITEM", "v1.EnvFromSource", matches) + self.assert_exists("Containers/ITEM/ports/ITEM", "v1.ContainerPort", matches) + self.assert_exists("capabilities", "v1.Capabilities", matches) + self.assert_exists("volumeDevices/ITEM", "v1.VolumeDevice", matches) + self.assert_exists("tolerations/ITEM", "v1.Toleration", matches) + self.assert_exists("spec/dataSource", "v1.TypedLocalObjectReference", matches) + self.assert_exists("affinity/nodeAffinity", "v1.NodeAffinity", matches) + self.assert_exists("imagePullSecrets/ITEM", "v1.LocalObjectReference", matches) + self.assert_exists("volumes/ITEM/nfs", "v1.NFSVolumeSource", matches) + self.assert_exists("volumes/ITEM/hostPath", "v1.HostPathVolumeSource", matches) + self.assert_exists("securityContext/sysctls/ITEM", "v1.Sysctl", matches) + + def test_cassop_crd(self): + with open( + os.path.join(test_data_dir, "cassop_crd.yaml"), + "r", + encoding="utf-8" + ) as operator_yaml: + crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) + spec_schema = extract_schema( + [], crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] + ) + matches = self.schema_matcher.find_matched_schemas(spec_schema) + self.assert_exists("affinity/nodeAffinity", "v1.NodeAffinity", matches) + self.assert_exists("podAffinityTerm/labelSelector", "v1.LabelSelector", matches) + self.assert_exists("podAffinityTerm/namespaceSelector", "v1.LabelSelector", matches) + self.assert_exists("requiredDuringSchedulingIgnoredDuringExecution/ITEM/labelSelector", "v1.LabelSelector", matches) + self.assert_exists("requiredDuringSchedulingIgnoredDuringExecution/ITEM/namespaceSelector", "v1.LabelSelector", matches) + self.assert_exists("configMapKeyRef", "v1.ConfigMapKeySelector", matches) + self.assert_exists("fieldRef", "v1.ObjectFieldSelector", matches) + self.assert_exists("secretKeyRef", "v1.SecretKeySelector", matches) + self.assert_exists("envFrom/ITEM", "v1.EnvFromSource", matches) + self.assert_exists("lifecycle/postStart/exec", "v1.ExecAction", matches) + self.assert_exists("httpGet/httpHeaders/ITEM", "v1.HTTPHeader", matches) + self.assert_exists("livenessProbe/exec", "v1.ExecAction", matches) + self.assert_exists("ports/ITEM", "v1.ContainerPort", matches) + self.assert_exists("readinessProbe/exec", "v1.ExecAction", matches) + self.assert_exists("readinessProbe/grpc", "v1.GRPCAction", matches) + self.assert_exists("containers/ITEM/securityContext", "v1.SecurityContext", matches) + self.assert_exists("volumeDevices/ITEM", "v1.VolumeDevice", matches) + self.assert_exists("volumeMounts/ITEM", "v1.VolumeMount", matches) + self.assert_exists("podTemplateSpec/spec/dnsConfig", "v1.PodDNSConfig", matches) + self.assert_exists("podTemplateSpec/spec/os", "v1.PodOS", matches) + self.assert_exists("spec/readinessGates/ITEM", "v1.PodReadinessGate", matches) + self.assert_exists("podTemplateSpec/spec/securityContext", "v1.PodSecurityContext", matches) + self.assert_exists("spec/tolerations/ITEM", "v1.Toleration", matches) + self.assert_exists("topologySpreadConstraints/ITEM/labelSelector", "v1.LabelSelector", matches) + self.assert_exists("volumes/ITEM/awsElasticBlockStore", "v1.AWSElasticBlockStoreVolumeSource", matches) + self.assert_exists("volumes/ITEM/azureDisk", "v1.AzureDiskVolumeSource", matches) + self.assert_exists("volumes/ITEM/azureFile", "v1.AzureFileVolumeSource", matches) + self.assert_exists("volumes/ITEM/cephfs", "v1.CephFSVolumeSource", matches) + self.assert_exists("volumes/ITEM/cinder", "v1.CinderVolumeSource", matches) + self.assert_exists("volumes/ITEM/configMap", "v1.ConfigMapVolumeSource", matches) + self.assert_exists("volumes/ITEM/csi", "v1.CSIVolumeSource", matches) + self.assert_exists("items/ITEM/fieldRef", "v1.ObjectFieldSelector", matches) + self.assert_exists("volumeClaimTemplate/spec/dataSource", "v1.TypedLocalObjectReference", matches) + # self.assert_exists("volumeClaimTemplate/spec/dataSourceRef", "v1.TypedObjectReference", matches) + self.assert_exists("volumeClaimTemplate/spec/selector", "v1.LabelSelector", matches) + self.assert_exists("volumes/ITEM/fc", "v1.FCVolumeSource", matches) + self.assert_exists("volumes/ITEM/flexVolume", "v1.FlexVolumeSource", matches) + self.assert_exists("volumes/ITEM/flocker", "v1.FlockerVolumeSource", matches) + self.assert_exists("volumes/ITEM/gcePersistentDisk", "v1.GCEPersistentDiskVolumeSource", matches) + self.assert_exists("volumes/ITEM/gitRepo", "v1.GitRepoVolumeSource", matches) + self.assert_exists("volumes/ITEM/glusterfs", "v1.GlusterfsVolumeSource", matches) + self.assert_exists("volumes/ITEM/hostPath", "v1.HostPathVolumeSource", matches) + self.assert_exists("volumes/ITEM/iscsi", "v1.ISCSIVolumeSource", matches) + self.assert_exists("volumes/ITEM/nfs", "v1.NFSVolumeSource", matches) + self.assert_exists("volumes/ITEM/persistentVolumeClaim", "v1.PersistentVolumeClaimVolumeSource", matches) + self.assert_exists("volumes/ITEM/photonPersistentDisk", "v1.PhotonPersistentDiskVolumeSource", matches) + self.assert_exists("volumes/ITEM/portworxVolume", "v1.PortworxVolumeSource", matches) + self.assert_exists("sources/ITEM/configMap", "v1.ConfigMapProjection", matches) + self.assert_exists("volumes/ITEM/quobyte", "v1.QuobyteVolumeSource", matches) + self.assert_exists("volumes/ITEM/rbd", "v1.RBDVolumeSource", matches) + self.assert_exists("volumes/ITEM/scaleIO", "v1.ScaleIOVolumeSource", matches) + self.assert_exists("volumes/ITEM/secret", "v1.SecretVolumeSource", matches) + self.assert_exists("volumes/ITEM/storageos", "v1.StorageOSVolumeSource", matches) + self.assert_exists("volumes/ITEM/vsphereVolume", "v1.VsphereVirtualDiskVolumeSource", matches) + self.assert_exists("ITEM/pvcSpec/dataSource", "v1.TypedLocalObjectReference", matches) + # self.assert_exists("ITEM/pvcSpec/dataSourceRef", "v1.TypedObjectReference", matches) + self.assert_exists("storageConfig/cassandraDataVolumeClaimSpec/dataSource", "v1.TypedLocalObjectReference", matches) + self.assert_exists("storageConfig/cassandraDataVolumeClaimSpec/dataSourceRef", "v1alpha2.ResourceClaimParametersReference", matches) + self.assert_exists("storageConfig/cassandraDataVolumeClaimSpec/selector", "v1.LabelSelector", matches) + self.assert_exists("spec/tolerations/ITEM", "v1.Toleration", matches) + + def test_strimzi_kafka_crd(self): + with open( + os.path.join(test_data_dir, "kafka_crd.yaml"), + "r", + encoding="utf-8", + ) as operator_yaml: + crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) + + spec_schema = extract_schema( + [], crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] + ) + matches = self.schema_matcher.find_matched_schemas(spec_schema) + self.assert_exists("namespaceSelector/matchExpressions/ITEM", "v1.LabelSelectorRequirement", matches) + self.assert_exists("labelSelector/matchExpressions/ITEM", "v1.LabelSelectorRequirement", matches) + self.assert_exists("container/securityContext", "v1.SecurityContext", matches) + self.assert_exists("resources/claims/ITEM", "v1.ResourceClaim", matches) + self.assert_exists("configMapKeyRef", "v1.ConfigMapKeySelector", matches) + self.assert_exists("imagePullSecrets/ITEM", "v1.LocalObjectReference", matches) + self.assert_exists("pod/securityContext", "v1.PodSecurityContext", matches) + self.assert_exists("affinity/nodeAffinity", "v1.NodeAffinity", matches) + self.assert_exists("tolerations/ITEM", "v1.Toleration", matches) + self.assert_exists("hostAliases/ITEM", "v1.HostAlias", matches) + self.assert_exists("networkPolicyPeers/ITEM/ipBlock", "v1.IPBlock", matches) def test_statefulset_match(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["override"] - ["properties"]["statefulSet"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["override"]["properties"][ + "statefulSet" + ], + ) self.assertTrue(StatefulSetSchema.Match(spec_schema)) def test_service_match(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["override"] - ["properties"]["service"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["override"]["properties"]["service"], + ) self.assertTrue(ServiceSchema.Match(spec_schema)) def test_affinity_match(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["affinity"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["affinity"], + ) self.assertTrue(AffinitySchema.Match(spec_schema)) def test_tolerations_match(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ArraySchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["tolerations"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["tolerations"], + ) self.assertTrue(TolerationsSchema.Match(spec_schema)) def test_tolerations_not_match(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["tolerations"] - ["items"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["tolerations"]["items"], + ) self.assertFalse(TolerationsSchema.Match(spec_schema)) def test_resources_match(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["resources"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["resources"], + ) self.assertTrue(ResourceRequirementsSchema.Match(spec_schema)) def test_container_match(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["override"] - ["properties"]["statefulSet"]["properties"]["spec"] - ["properties"]["template"]["properties"]["spec"] - ["properties"]["containers"]["items"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["override"]["properties"][ + "statefulSet" + ][ + "properties" + ][ + "spec" + ][ + "properties" + ][ + "template" + ][ + "properties" + ][ + "spec" + ][ + "properties" + ][ + "containers" + ][ + "items" + ], + ) self.assertTrue(ContainerSchema.Match(spec_schema)) - with open(os.path.join(test_data_dir, "psmdb.percona.com_perconaservermongodbs.yaml"), - "r") as operator_yaml: + with open( + os.path.join( + test_data_dir, "psmdb.percona.com_perconaservermongodbs.yaml" + ), + "r", + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) - spec_schema = ObjectSchema(["root"], - crd["spec"]["versions"][-1] - ["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"] - ["replsets"]["items"]["properties"] - ["sidecars"]["items"]) + spec_schema = ObjectSchema( + ["root"], + crd["spec"]["versions"][-1]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["replsets"]["items"]["properties"][ + "sidecars" + ][ + "items" + ], + ) self.assertTrue(ContainerSchema.Match(spec_schema)) def test_resources_match(self): - with open(os.path.join(test_data_dir, "crdb_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "crdb_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) tls_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["ingress"] - ["properties"]["sql"]["properties"]["tls"]["items"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["ingress"]["properties"]["sql"][ + "properties" + ][ + "tls" + ][ + "items" + ], + ) self.assertTrue(IngressTLSSchema.Match(tls_schema)) self.assertTrue(field_matched(tls_schema, IngressTLSSchema)) def test_pod_spec_match(self): - with open(os.path.join(test_data_dir, "cassop_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "cassop_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = extract_schema_with_value_generator( [], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["podTemplateSpec"] - ["properties"]["spec"]["properties"]["containers"] - ["items"]["properties"]["livenessProbe"]) - # tuples = find_all_matched_schemas_type(spec_schema) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["podTemplateSpec"]["properties"][ + "spec" + ][ + "properties" + ][ + "containers" + ][ + "items" + ][ + "properties" + ][ + "livenessProbe" + ], + ) + # tuples = find_all_matches_schemas_type(spec_schema) # for tuple in tuples: - # print(f"Found matched schema: {tuple[0].path} -> {tuple[1]}") + # print(f"Found matches schema: {tuple[0].path} -> {tuple[1]}") # k8s_schema = K8sField(tuple[0].path, tuple[1]) print(LivenessProbeSchema.Match(spec_schema)) def test_find_matches(self): - with open(os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r") as operator_yaml: + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), "r" + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = extract_schema( - [], crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"]) + [], crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] + ) print(find_all_matched_schemas(spec_schema)) def test_pvc_match(self): - with open(os.path.join(test_data_dir, "databases.spotahome.com_redisfailovers.yaml"), "r") as operator_yaml: + with open( + os.path.join( + test_data_dir, "databases.spotahome.com_redisfailovers.yaml" + ), + "r", + ) as operator_yaml: crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) spec_schema = ObjectSchema( ["root"], - crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] - ["properties"]["spec"]["properties"]["redis"] - ["properties"]["storage"]["properties"] - ["persistentVolumeClaim"]) + crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"][ + "properties" + ]["spec"]["properties"]["redis"]["properties"]["storage"][ + "properties" + ][ + "persistentVolumeClaim" + ], + ) self.assertTrue(PersistentVolumeClaimSchema.Match(spec_schema)) From 2df2fb7c9dba2ce26b17d5fca91977ee5cf25a1d Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Thu, 11 Jan 2024 14:11:27 -0500 Subject: [PATCH 6/9] Match descendants of matched schemas --- acto/input/k8s_schemas.py | 1 - test/integration_tests/test_known_schemas.py | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py index b5d021189f..8667728be1 100644 --- a/acto/input/k8s_schemas.py +++ b/acto/input/k8s_schemas.py @@ -390,7 +390,6 @@ def find_matched_schemas(self, schema: BaseSchema) -> BaseSchema: if matched_schemas: idx = self._rank_matched_k8s_schemas(schema, matched_schemas) matched_schemas = [matched_schemas[idx]] - return matched_schemas if isinstance(schema, ObjectSchema): for sub_schema in schema.properties.values(): matched_schemas.extend(self.find_matched_schemas(sub_schema)) diff --git a/test/integration_tests/test_known_schemas.py b/test/integration_tests/test_known_schemas.py index a829204cbc..8231c67b9f 100644 --- a/test/integration_tests/test_known_schemas.py +++ b/test/integration_tests/test_known_schemas.py @@ -168,6 +168,10 @@ def test_strimzi_kafka_crd(self): self.assert_exists("tolerations/ITEM", "v1.Toleration", matches) self.assert_exists("hostAliases/ITEM", "v1.HostAlias", matches) self.assert_exists("networkPolicyPeers/ITEM/ipBlock", "v1.IPBlock", matches) + # The following are schemas that are descendants of already matched schemas + self.assert_exists("capabilities", "v1.Capabilities", matches) + self.assert_exists("seLinuxOptions", "v1.SELinuxOptions", matches) + self.assert_exists("seccompProfile", "v1.SeccompProfile", matches) def test_statefulset_match(self): with open( From 4994616c9a77fb2424961c71677b3af50527d929 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Thu, 11 Jan 2024 17:20:07 -0500 Subject: [PATCH 7/9] Rename K8s dict and list schema class --- acto/input/k8s_schemas.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py index 8667728be1..b92cc3cf01 100644 --- a/acto/input/k8s_schemas.py +++ b/acto/input/k8s_schemas.py @@ -135,8 +135,8 @@ def dump_schema(self) -> dict: return {"type": "number"} -class KubernetesDictSchema(KubernetesSchema): - """Class for Kubernetes dict schema matching""" +class KubernetesMapSchema(KubernetesSchema): + """Class for Kubernetes map schema matching""" def __init__(self, value_cls: KubernetesSchema) -> None: super().__init__() @@ -163,8 +163,8 @@ def dump_schema(self) -> dict: } -class KubernetesListSchema(KubernetesSchema): - """Class for Kubernetes list schema matching""" +class KubernetesArraySchema(KubernetesSchema): + """Class for Kubernetes array schema matching""" def __init__(self, item_cls: KubernetesSchema) -> None: super().__init__() @@ -313,12 +313,12 @@ def resolve(schema_spec: dict) -> KubernetesSchema: return KubernetesFloatSchema() elif schema_spec["type"] == "object": if "additionalProperties" in schema_spec: - return KubernetesDictSchema( + return KubernetesMapSchema( resolve(schema_spec["additionalProperties"]) ) return KubernetesOpaqueSchema() elif schema_spec["type"] == "array": - return KubernetesListSchema(resolve(schema_spec["items"])) + return KubernetesArraySchema(resolve(schema_spec["items"])) else: raise KeyError(f"Cannot resolve type {schema_spec}") From 4a9281c560206ed0567c20ddeead26462811b638 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Sat, 13 Jan 2024 10:48:27 -0500 Subject: [PATCH 8/9] Use YAML for dumped schema files --- acto/input/k8s_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acto/input/k8s_schemas.py b/acto/input/k8s_schemas.py index b92cc3cf01..049dfe927e 100644 --- a/acto/input/k8s_schemas.py +++ b/acto/input/k8s_schemas.py @@ -459,5 +459,5 @@ def dump_k8s_schemas(self) -> dict: # print("Dumping k8s schemas to './schemas' ...") # os.makedirs("schemas", exist_ok=True) # for schema_name, schema in schema_matcher.dump_k8s_schemas().items(): - # with open(f"schemas/{schema_name}.json", "w") as f: + # with open(f"schemas/{schema_name}.yaml", "w") as f: # yaml.dump(schema, f, indent=2) From 1d3c829fb0a8ee6baa7c14353ec4296a2d34d1b1 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Sat, 13 Jan 2024 15:13:40 -0500 Subject: [PATCH 9/9] Added generator decorator and tests for it - generator decorator supports k8s schema name, field name, field type, paths, and priority configuration --- acto/input/generator.py | 163 ++++++++++++++++++ .../test_testcase_generator_decorator.py | 153 ++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 acto/input/generator.py create mode 100644 test/integration_tests/test_testcase_generator_decorator.py diff --git a/acto/input/generator.py b/acto/input/generator.py new file mode 100644 index 0000000000..c345de3ea9 --- /dev/null +++ b/acto/input/generator.py @@ -0,0 +1,163 @@ +"""This module provides a decorator for generating test cases for a schema and +a function to get all test cases for a schema.""" + +from collections import namedtuple +from typing import Callable, Literal, Optional + +from acto.input.k8s_schemas import KubernetesObjectSchema, KubernetesSchema +from acto.input.testcase import TestCase +from acto.schema import ( + AnyOfSchema, + ArraySchema, + BaseSchema, + BooleanSchema, + IntegerSchema, + NumberSchema, + ObjectSchema, + OneOfSchema, + OpaqueSchema, + StringSchema, +) + +TestGenerator = namedtuple( + "TestGeneratorObject", + [ + "k8s_schema_name", + "field_name", + "field_type", + "paths", + "priority", + "func", + ], +) + + +# global variable for registered test generators +test_generators: TestGenerator = [] + + +def generator( + k8s_schema_name: Optional[str] = None, + field_name: Optional[str] = None, + field_type: Optional[ + Literal[ + "AnyOf", + "Array", + "Boolean", + "Integer", + "Number", + "Object", + "OneOf", + "Opaque", + "String", + ] + ] = None, + paths: Optional[list[str]] = None, + priority: int = 0, +): + """Annotates a function as a test generator + + Args: + k8s_schema_name (str, optional): Kubernetes schema name. Defaults to None. + field_name (str, optional): field/property name. Defaults to None. + field_type (str, optional): field/property type. Defaults to None. + paths (list[str], optional): Path suffixes. Defaults to None. + priority (int, optional): Priority. Defaults to 0.""" + assert ( + k8s_schema_name is not None + or field_name is not None + or field_type is not None + or paths is not None + ), "One of k8s_schema_name, schema_name, schema_type, paths must be specified" + + def wrapped_func(func: Callable[[BaseSchema], list[TestCase]]): + gen_obj = TestGenerator( + k8s_schema_name, + field_name, + field_type, + paths, + priority, + func, + ) + test_generators.append(gen_obj) + return func + + return wrapped_func + + +def get_testcases( + schema: BaseSchema, + matched_schemas: [tuple[BaseSchema, KubernetesSchema]], +) -> list[tuple[list[str], TestCase]]: + """Get all test cases for a schema from registered test generators""" + matched_schemas: dict[str, KubernetesObjectSchema] = { + "/".join(s.path): m for s, m in matched_schemas + } + + def get_testcases_helper(schema: BaseSchema, field_name: Optional[str]): + # print(schema_name, schema.path, type(schema)) + test_cases = [] + generator_candidates = [] + # check paths + path_str = "/".join(schema.path) + matched_schema = matched_schemas.get(path_str) + for test_gen in test_generators: + # check paths + for path in test_gen.paths or []: + if path_str.endswith(path): + generator_candidates.append(test_gen) + continue + + # check field name + if ( + test_gen.field_name is not None + and test_gen.field_name == field_name + ): + generator_candidates.append(test_gen) + continue + + # check k8s schema name + if ( + test_gen.k8s_schema_name is not None + and matched_schema is not None + and matched_schema.k8s_schema_name.endswith( + test_gen.k8s_schema_name + ) + ): + generator_candidates.append(test_gen) + continue + + # check type + matching_types = { + "AnyOf": AnyOfSchema, + "Array": ArraySchema, + "Boolean": BooleanSchema, + "Integer": IntegerSchema, + "Number": NumberSchema, + "Object": ObjectSchema, + "OneOf": OneOfSchema, + "Opaque": OpaqueSchema, + "String": StringSchema, + } + if schema_type_obj := matching_types.get(test_gen.field_type): + if isinstance(schema, schema_type_obj): + generator_candidates.append(test_gen) + + # sort by priority + generator_candidates.sort(key=lambda x: x.priority, reverse=True) + if len(generator_candidates) > 0: + test_cases.append( + (schema.path, generator_candidates[0].func(schema)) + ) + + # check sub schemas + if isinstance(schema, ArraySchema): + test_cases.extend( + get_testcases_helper(schema.get_item_schema(), "ITEM") + ) + elif isinstance(schema, ObjectSchema): + for field, sub_schema in schema.properties.items(): + test_cases.extend(get_testcases_helper(sub_schema, field)) + return test_cases + + return get_testcases_helper(schema, None) diff --git a/test/integration_tests/test_testcase_generator_decorator.py b/test/integration_tests/test_testcase_generator_decorator.py new file mode 100644 index 0000000000..c581fbc1eb --- /dev/null +++ b/test/integration_tests/test_testcase_generator_decorator.py @@ -0,0 +1,153 @@ +# pylint: disable=missing-docstring, line-too-long + +import os +import pathlib +import unittest + +import yaml + +from acto.input.generator import generator, get_testcases, test_generators +from acto.input.k8s_schemas import K8sSchemaMatcher +from acto.input.testcase import TestCase +from acto.schema import extract_schema + +test_dir = pathlib.Path(__file__).parent.resolve() +test_data_dir = os.path.join(test_dir, "test_data") + + +def gen(_): + return [TestCase("test", lambda x: True, lambda x: None, lambda x: None)] + + +class TestSchema(unittest.TestCase): + """This class tests the schema matching code for various CRDs.""" + + @classmethod + def setUpClass(cls): + with open( + os.path.join(test_data_dir, "rabbitmq_crd.yaml"), + "r", + encoding="utf-8", + ) as operator_yaml: + rabbitmq_crd = yaml.load(operator_yaml, Loader=yaml.FullLoader) + schema_matcher = K8sSchemaMatcher.from_version("1.29") + cls.spec_schema = extract_schema( + [], rabbitmq_crd["spec"]["versions"][0]["schema"]["openAPIV3Schema"] + ) + cls.matches = schema_matcher.find_matched_schemas(cls.spec_schema) + + def test_path_suffix(self): + test_generators.clear() + generator(paths=["serviceAccountToken/expirationSeconds"])(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 1) + + test_generators.clear() + generator( + paths=[ + "serviceAccountToken/expirationSeconds", + "volumes/ITEM/quobyte/user", + ] + )(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 2) + + def test_k8s_schema_name(self): + test_generators.clear() + generator(k8s_schema_name="v1.NodeAffinity")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 2) + + test_generators.clear() + generator(k8s_schema_name="HTTPHeader")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 15) + + def test_field_name(self): + test_generators.clear() + generator(field_name="ports")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 4) + + test_generators.clear() + generator(field_name="image")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 5) + + def test_field_type(self): + test_generators.clear() + generator(field_type="AnyOf")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 38) + + test_generators.clear() + generator(field_type="Array")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 173) + + test_generators.clear() + generator(field_type="Boolean")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 73) + + test_generators.clear() + generator(field_type="Integer")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 106) + + test_generators.clear() + generator(field_type="Number")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 106) + + test_generators.clear() + generator(field_type="Object")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 368) + + # test_generators.clear() + # generator(field_type="OneOf")(gen) + # testcases = get_testcases(self.spec_schema, self.matches) + # self.assertEqual(len(testcases), 0) + + # test_generators.clear() + # generator(field_type="Opaque")(gen) + # testcases = get_testcases(self.spec_schema, self.matches) + # self.assertEqual(len(testcases), 0) + + test_generators.clear() + generator(field_type="String")(gen) + testcases = get_testcases(self.spec_schema, self.matches) + self.assertEqual(len(testcases), 550) + + def test_priority(self): + test_generators.clear() + + @generator(field_type="Integer", priority=0) + def gen0(_): + return [ + TestCase( + "integer-test", + lambda x: True, + lambda x: None, + lambda x: None, + ) + ] + + @generator(field_name="replicas", priority=1) + def gen1(_): + return [ + TestCase( + "replicas-test", + lambda x: True, + lambda x: None, + lambda x: None, + ) + ] + + testcases = get_testcases(self.spec_schema, self.matches) + for path, tests in testcases: + if path[-1] == "replicas": + self.assertEqual(tests[0].name, "replicas-test") + else: + self.assertEqual(tests[0].name, "integer-test")