diff --git a/kubernetes/autoscaling.py b/kubernetes/autoscaling.py index 287c5b8..2736d5e 100644 --- a/kubernetes/autoscaling.py +++ b/kubernetes/autoscaling.py @@ -44,7 +44,7 @@ def body(self): class PodDisruptionBudget(KubernetesResource): kind: str = "PodDisruptionBudget" - api_version: str = "policy/v1beta1" + api_version: str = "policy/v1" def body(self): super().body() @@ -77,7 +77,7 @@ def body(self): class HorizontalPodAutoscaler(KubernetesResource): kind: str = "HorizontalPodAutoscaler" - api_version: str = "autoscaling.k8s.io/v2beta2" + api_version: str = "autoscaling.k8s.io/v2" def body(self): super().body() diff --git a/kubernetes/certmanager.py b/kubernetes/certmanager.py index 292cd92..5e07fd6 100644 --- a/kubernetes/certmanager.py +++ b/kubernetes/certmanager.py @@ -13,7 +13,7 @@ class CertManagerIssuer(KubernetesResource): def body(self): config = self.config super().body() - self.root.spec = config.get("spec") + self.root.spec = config.spec @kgenlib.register_generator(path="certmanager.cluster_issuer") @@ -24,7 +24,7 @@ class CertManagerClusterIssuer(KubernetesResource): def body(self): config = self.config super().body() - self.root.spec = config.get("spec") + self.root.spec = config.spec @kgenlib.register_generator(path="certmanager.certificate") @@ -35,4 +35,4 @@ class CertManagerCertificate(KubernetesResource): def body(self): config = self.config super().body() - self.root.spec = config.get("spec") + self.root.spec = config.spec diff --git a/kubernetes/common.py b/kubernetes/common.py index d218c0e..2fc6748 100644 --- a/kubernetes/common.py +++ b/kubernetes/common.py @@ -358,6 +358,10 @@ class VPAConfigSpec(kgenlib.BaseModel): update_mode: str = "Auto" resource_policy: Dict[str, List[Dict]] = {} +class HPAConfigSpec(kgenlib.BaseModel): + min_replicas: Optional[int] = None + max_replicas: Optional[int] = None + metrics: List[Dict[str, Any]] = [] class ServiceMonitororConfigSpec(kgenlib.BaseModel): endpoints: list = [] @@ -382,6 +386,7 @@ class WorkloadConfigSpec(KubernetesResourceSpec, ContainerSpec): application: Optional[str] = None auto_pdb: bool = False backend_config: dict = {} + frontend_config: dict = {} cluster_role: Optional[Dict] = None containers: dict = {} deployment_progress_deadline_seconds: int | None = None @@ -389,7 +394,7 @@ class WorkloadConfigSpec(KubernetesResourceSpec, ContainerSpec): grace_period: int = 30 host_network: Optional[bool] = None host_pid: Optional[bool] = None - hpa: dict = {} + hpa: Optional[HPAConfigSpec] = None image_pull_secrets: list = [] init_containers: Optional[Dict[str, Union[InitContainerSpec, None]]] = {} istio_policy: dict = {} diff --git a/kubernetes/gke.py b/kubernetes/gke.py index 82806c7..5662ee0 100644 --- a/kubernetes/gke.py +++ b/kubernetes/gke.py @@ -2,7 +2,8 @@ logger = logging.getLogger(__name__) -from .common import KubernetesResource +from .common import KubernetesResource, kgenlib +from typing import Any class BackendConfig(KubernetesResource): @@ -11,4 +12,41 @@ class BackendConfig(KubernetesResource): def body(self): super().body() - self.root.spec = self.config.backend_config + spec = self.spec + self.root.spec = spec + + +@kgenlib.register_generator(path="generators.kubernetes.backend_config") +class BackendConfigGenerator(kgenlib.BaseStore): + name: str + config: Any + + def body(self): + name = self.name + config = self.config + spec = self.config.spec + backend_config = BackendConfig(name=name, config=config, spec=spec) + self.add(backend_config) + + +class FrontendConfig(KubernetesResource): + kind: str = "FrontendConfig" + api_version: str = "networking.gke.io/v1beta1" + + def body(self): + super().body() + spec = self.spec + self.root.spec = spec + + +@kgenlib.register_generator(path="generators.kubernetes.frontend_config") +class FrontendConfigGenerator(kgenlib.BaseStore): + name: str + config: Any + + def body(self): + name = self.name + config = self.config + spec = self.config.spec + frontend_config = FrontendConfig(name=name, config=config, spec=spec) + self.add(frontend_config) \ No newline at end of file diff --git a/kubernetes/networking.py b/kubernetes/networking.py index b321ab7..0667e76 100644 --- a/kubernetes/networking.py +++ b/kubernetes/networking.py @@ -32,8 +32,8 @@ def body(self): config = self.config if config.default_backend: - self.root.spec.backend.service.name = config.default_backend.get("name") - self.root.spec.backend.service.port = config.default_backend.get("port", 80) + self.root.spec.defaultBackend.service.name = config.default_backend.get("name") + self.root.spec.defaultBackend.service.port = config.default_backend.get("port", 80) if config.paths: host = config.host paths = config.paths @@ -47,7 +47,7 @@ def body(self): class GoogleManagedCertificate(KubernetesResource): kind: str = "ManagedCertificate" - api_version: str = "networking.gke.io/v1beta1" + api_version: str = "networking.gke.io/v1" def body(self): super().body() @@ -410,6 +410,7 @@ def body(self): ) self.add( GoogleManagedCertificate( - name=certificate_name, config={"domains": domains} + name=certificate_name, namespace=self.config.namespace, + config={"domains": domains} ) ) diff --git a/kubernetes/rbac.py b/kubernetes/rbac.py index bbc44f7..6cbe20b 100644 --- a/kubernetes/rbac.py +++ b/kubernetes/rbac.py @@ -31,6 +31,10 @@ def body(self): else: self.name = config.name or self.name super().body() + # Force the name again after super().body() + # This is needed for when we are setting service_account.name. + # Wihthout this, only labels.name is set correctly + self.root.metadata.name = self.name if self.spec: self.add_annotations(self.spec.annotations) diff --git a/kubernetes/workloads.py b/kubernetes/workloads.py index 9c79c2b..a104667 100644 --- a/kubernetes/workloads.py +++ b/kubernetes/workloads.py @@ -24,7 +24,7 @@ WorkloadTypes, kgenlib, ) -from .gke import BackendConfig +from .gke import BackendConfig, FrontendConfig from .istio import IstioPolicy from .networking import NetworkPolicy, Service from .prometheus import PrometheusRule, ServiceMonitor @@ -117,7 +117,7 @@ def body(self): affinity = self.root.spec.template.spec.affinity if config.prefer_pods_in_node_with_expression and not config.node_selector: affinity.nodeAffinity.setdefault( - "preferredDuringSchedulingIgnoredDuringExecutio", [] + "preferredDuringSchedulingIgnoredDuringExecution", [] ) affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.append( { @@ -137,7 +137,7 @@ def body(self): "podAffinityTerm": { "labelSelector": { "matchExpressions": [ - {"key": "app", "operator": "In", "values": [name]} + {"key": "name", "operator": "In", "values": [name]} ] }, "topologyKey": "kubernetes.io/hostname", @@ -155,7 +155,7 @@ def body(self): "podAffinityTerm": { "labelSelector": { "matchExpressions": [ - {"key": "app", "operator": "In", "values": [name]} + {"key": "name", "operator": "In", "values": [name]} ] }, "topologyKey": "topology.kubernetes.io/zone", @@ -338,7 +338,7 @@ class Container(BaseModel): @staticmethod def find_key_in_config(key, configs): for name, config in configs.items(): - if key in config.data.keys(): + if key in config.data or key in config.string_data: return name raise ( BaseException( @@ -504,6 +504,7 @@ def body(self): apply_patches=[ "generators.manifest.default_config", 'applications."{application}".component_defaults', + 'generators.manifest.resource_defaults.{type}' ], ) class Components(kgenlib.BaseStore): @@ -521,6 +522,7 @@ def _add_component( if config_attr and getattr(self.config, config_attr): spec = spec or getattr(self.config, config_attr, {}) name = name or self.name + component = component_class( name=name, config=self.config, spec=spec, workload=workload, **kwargs ) @@ -528,6 +530,7 @@ def _add_component( logger.debug(f"Added component {component.root.metadata} for {self.name}.") return component + def _generate_and_add_multiple_objects( self, generating_class, config_attr, workload ): @@ -630,14 +633,16 @@ def body(self): self._add_component( ClusterRoleBinding, "cluster_role", role=role, sa=sa ) + self._add_component(BackendConfig, "backend_config", spec=self.config.backend_config) + self._add_component(FrontendConfig, "frontend_config", spec=self.config.frontend_config) - self._add_component(BackendConfig, "backend_config") # Handling a special case where pdb_min_available or auto_pdb is set, but config.type isn't "job" if self.config.type != "job" and ( self.config.pdb_min_available or self.config.auto_pdb ): - self._add_component(PodDisruptionBudget, workload=workload) + config_attr = "pdb_min_available" if self.config.pdb_min_available else "auto_pdb" + self._add_component(PodDisruptionBudget, config_attr, workload=workload) self.add(workload)