diff --git a/src/tools/genpolicy/src/deployment.rs b/src/tools/genpolicy/src/deployment.rs new file mode 100644 index 000000000..397d1344d --- /dev/null +++ b/src/tools/genpolicy/src/deployment.rs @@ -0,0 +1,130 @@ +// Copyright (c) 2023 Microsoft Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +// Allow K8s YAML field names. +#![allow(non_snake_case)] + +use crate::obj_meta; +use crate::pod; +use crate::pod_template; +use crate::policy; +use crate::settings; +use crate::yaml; + +use async_trait::async_trait; +use protocols::agent; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +/// Reference / Kubernetes API / Workload Resources / Deployment. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Deployment { + apiVersion: String, + kind: String, + metadata: obj_meta::ObjectMeta, + spec: DeploymentSpec, + + #[serde(skip)] + doc_mapping: serde_yaml::Value, +} + +/// Reference / Kubernetes API / Workload Resources / Deployment. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct DeploymentSpec { + #[serde(skip_serializing_if = "Option::is_none")] + replicas: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + selector: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + strategy: Option, + + template: pod_template::PodTemplateSpec, + // TODO: additional fields. +} + +/// Reference / Kubernetes API / Workload Resources / Deployment. +#[derive(Clone, Debug, Serialize, Deserialize)] +struct DeploymentStrategy { + #[serde(skip_serializing_if = "Option::is_none")] + r#type: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + rollingUpdate: Option, +} + +/// Reference / Kubernetes API / Workload Resources / Deployment. +#[derive(Clone, Debug, Serialize, Deserialize)] +struct RollingUpdateDeployment { + #[serde(skip_serializing_if = "Option::is_none")] + maxSurge: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + maxUnavailable: Option, +} + +#[async_trait] +impl yaml::K8sResource for Deployment { + async fn init( + &mut self, + use_cache: bool, + doc_mapping: &serde_yaml::Value, + _silent_unsupported_fields: bool, + ) { + yaml::k8s_resource_init(&mut self.spec.template.spec, use_cache).await; + self.doc_mapping = doc_mapping.clone(); + } + + fn get_sandbox_name(&self) -> Option { + None + } + + fn get_namespace(&self) -> String { + self.metadata.get_namespace() + } + + fn get_container_mounts_and_storages( + &self, + policy_mounts: &mut Vec, + storages: &mut Vec, + container: &pod::Container, + settings: &settings::Settings, + ) { + if let Some(volumes) = &self.spec.template.spec.volumes { + yaml::get_container_mounts_and_storages( + policy_mounts, + storages, + container, + settings, + volumes, + ); + } + } + + fn generate_policy(&self, agent_policy: &policy::AgentPolicy) -> String { + agent_policy.generate_policy(self) + } + + fn serialize(&mut self, policy: &str) -> String { + yaml::add_policy_annotation(&mut self.doc_mapping, "spec.template.metadata", policy); + serde_yaml::to_string(&self.doc_mapping).unwrap() + } + + fn get_containers(&self) -> &Vec { + &self.spec.template.spec.containers + } + + fn get_annotations(&self) -> &Option> { + &self.spec.template.metadata.annotations + } + + fn use_host_network(&self) -> bool { + if let Some(host_network) = self.spec.template.spec.hostNetwork { + return host_network; + } + false + } +} diff --git a/src/tools/genpolicy/src/main.rs b/src/tools/genpolicy/src/main.rs index c56d01310..8945417ce 100644 --- a/src/tools/genpolicy/src/main.rs +++ b/src/tools/genpolicy/src/main.rs @@ -10,6 +10,7 @@ use log::{debug, info}; mod config_map; mod containerd; mod daemon_set; +mod deployment; mod mount_and_storage; mod no_policy; mod obj_meta; diff --git a/src/tools/genpolicy/src/yaml.rs b/src/tools/genpolicy/src/yaml.rs index 8703c0dc9..13e5f01e4 100644 --- a/src/tools/genpolicy/src/yaml.rs +++ b/src/tools/genpolicy/src/yaml.rs @@ -8,6 +8,7 @@ use crate::config_map; use crate::daemon_set; +use crate::deployment; use crate::mount_and_storage; use crate::no_policy; use crate::pod; @@ -108,6 +109,14 @@ pub fn new_k8s_resource( debug!("{:#?}", &daemon); Ok((boxed::Box::new(daemon), header.kind)) } + "Deployment" => { + let deployment: deployment::Deployment = serde_ignored::deserialize(d, |path| { + handle_unused_field(&path.to_string(), silent_unsupported_fields); + }) + .unwrap(); + debug!("{:#?}", &deployment); + Ok((boxed::Box::new(deployment), header.kind)) + } "Pod" => { let pod: pod::Pod = serde_ignored::deserialize(d, |path| { handle_unused_field(&path.to_string(), silent_unsupported_fields);