Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved MirrordPolicy to a separate module, added MirrordClusterPolicy #2974

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/+cluster-policy.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added custom resource definition for cluster-wide mirrord policy - `MirrordClusterPolicy`.
53 changes: 4 additions & 49 deletions mirrord/operator/src/crd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ use schemars::JsonSchema;
use semver::Version;
use serde::{Deserialize, Serialize};

use self::label_selector::LabelSelector;
#[cfg(feature = "client")]
use crate::client::error::OperatorApiError;
use crate::types::LicenseInfoOwned;

pub mod kafka;
pub mod kube_target;
pub mod label_selector;
pub mod policy;

pub const TARGETLESS_TARGET_NAME: &str = "targetless";

Expand Down Expand Up @@ -52,7 +52,9 @@ impl TargetCrd {
/// # Warning
///
/// Do **not** change url paths here, even if the operator recognizes the other format.
/// It can break exisiting [`MirrordPolicy`]s (see [`MirrordPolicySpec::target_path`]).
/// It can break exisiting [`policy::MirrordPolicy`]s and [`policy::MirrordClusterPolicy`]
/// (see [`policy::MirrordPolicySpec::target_path`] and
/// [`policy::MirrordClusterPolicySpec::target_path`]).
pub fn urlfied_name(target: &Target) -> String {
let (type_name, target, container) = match target {
Target::Deployment(target) => ("deploy", &target.deployment, &target.container),
Expand Down Expand Up @@ -353,53 +355,6 @@ pub struct CopyTargetStatus {
pub creator_session: Session,
}

/// Features and operations that can be blocked by a `MirrordPolicy`.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, JsonSchema)]
#[serde(rename_all = "kebab-case")] // StealWithoutFilter -> steal-without-filter in yaml.
pub enum BlockedFeature {
/// Blocks stealing traffic in any way (without or without filter).
Steal,

/// Blocks stealing traffic without specifying (any) filter. Client can still specify a
/// filter that matches anything.
StealWithoutFilter,

/// Blocks mirroring traffic.
Mirror,

/// So that the operator is able to list all policies with [`kube::Api`],
/// even if it doesn't recognize blocked features used in some of them.
#[schemars(skip)]
#[serde(other, skip_serializing)]
Unknown,
}

/// Custom resource for policies that limit what mirrord features users can use.
#[derive(CustomResource, Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[kube(
// The operator group is handled by the operator, we want policies to be handled by k8s.
group = "policies.mirrord.metalbear.co",
version = "v1alpha",
kind = "MirrordPolicy",
namespaced
)]
#[serde(rename_all = "camelCase")] // target_path -> targetPath in yaml.
pub struct MirrordPolicySpec {
/// Specify the targets for which this policy applies, in the pod/my-pod deploy/my-deploy
/// notation. Targets can be matched using `*` and `?` where `?` matches exactly one
/// occurrence of any character and `*` matches arbitrary many (including zero) occurrences
/// of any character. If not specified, this policy does not depend on the target's path.
pub target_path: Option<String>,

/// If specified in a policy, the policy will only apply to targets with labels that match all
/// of the selector's rules.
pub selector: Option<LabelSelector>,

// TODO: make the k8s list type be set/map to prevent duplicates.
/// List of features and operations blocked by this policy.
pub block: Vec<BlockedFeature>,
}

/// Set where the application reads the name of the queue from, so that mirrord can find that queue,
/// split it, and temporarily change the name there to the name of the branch queue when splitting.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize, JsonSchema)]
Expand Down
88 changes: 88 additions & 0 deletions mirrord/operator/src/crd/policy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use kube::CustomResource;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use super::label_selector::LabelSelector;

/// Features and operations that can be blocked by `mirrordpolicies` and `mirrordclusterpolicies`.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, JsonSchema)]
#[serde(rename_all = "kebab-case")] // StealWithoutFilter -> steal-without-filter in yaml.
pub enum BlockedFeature {
/// Blocks stealing traffic in any way (without or without filter).
Steal,

/// Blocks stealing traffic without specifying (any) filter. Client can still specify a
/// filter that matches anything.
StealWithoutFilter,

/// Blocks mirroring traffic.
Mirror,

/// So that the operator is able to list all policies with [`kube::Api`],
/// even if it doesn't recognize blocked features used in some of them.
#[schemars(skip)]
#[serde(other, skip_serializing)]
Unknown,
}

/// Custom resource for policies that limit what mirrord features users can use.
///
/// This policy applies only to resources living in the same namespace.
#[derive(CustomResource, Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[kube(
// The operator group is handled by the operator, we want policies to be handled by k8s.
group = "policies.mirrord.metalbear.co",
version = "v1alpha",
kind = "MirrordPolicy",
namespaced
)]
#[serde(rename_all = "camelCase")] // target_path -> targetPath in yaml.
pub struct MirrordPolicySpec {
/// Specify the targets for which this policy applies, in the pod/my-pod deploy/my-deploy
/// notation. Targets can be matched using `*` and `?` where `?` matches exactly one
/// occurrence of any character and `*` matches arbitrary many (including zero) occurrences
/// of any character. If not specified, this policy does not depend on the target's path.
pub target_path: Option<String>,

/// If specified in a policy, the policy will only apply to targets with labels that match all
/// of the selector's rules.
pub selector: Option<LabelSelector>,

// TODO: make the k8s list type be set/map to prevent duplicates.
/// List of features and operations blocked by this policy.
pub block: Vec<BlockedFeature>,
}

/// Custom cluster-wide resource for policies that limit what mirrord features users can use.
///
/// This policy applies to resources across all namespaces in the cluster.
#[derive(CustomResource, Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[kube(
// The operator group is handled by the operator, we want policies to be handled by k8s.
group = "policies.mirrord.metalbear.co",
version = "v1alpha",
kind = "MirrordClusterPolicy"
)]
#[serde(rename_all = "camelCase")] // target_path -> targetPath in yaml.
pub struct MirrordClusterPolicySpec {
/// Specify the targets for which this policy applies, in the pod/my-pod deploy/my-deploy
/// notation. Targets can be matched using `*` and `?` where `?` matches exactly one
/// occurrence of any character and `*` matches arbitrary many (including zero) occurrences
/// of any character. If not specified, this policy does not depend on the target's path.
pub target_path: Option<String>,

/// If specified in a policy, the policy will only apply to targets with labels that match all
/// of the selector's rules.
pub selector: Option<LabelSelector>,

// TODO: make the k8s list type be set/map to prevent duplicates.
/// List of features and operations blocked by this policy.
pub block: Vec<BlockedFeature>,
}

#[test]
fn check_one_api_group() {
use kube::Resource;

assert_eq!(MirrordPolicy::group(&()), MirrordClusterPolicy::group(&()),)
}
12 changes: 10 additions & 2 deletions mirrord/operator/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ use thiserror::Error;

use crate::crd::{
kafka::{MirrordKafkaClientConfig, MirrordKafkaEphemeralTopic, MirrordKafkaTopicsConsumer},
MirrordOperatorUser, MirrordPolicy, MirrordSqsSession, MirrordWorkloadQueueRegistry, TargetCrd,
policy::{MirrordClusterPolicy, MirrordPolicy},
MirrordOperatorUser, MirrordSqsSession, MirrordWorkloadQueueRegistry, TargetCrd,
};

pub static OPERATOR_NAME: &str = "mirrord-operator";
Expand Down Expand Up @@ -230,6 +231,9 @@ impl OperatorSetup for Operator {
writer.write_all(b"---\n")?;
MirrordPolicy::crd().to_writer(&mut writer)?;

writer.write_all(b"---\n")?;
MirrordClusterPolicy::crd().to_writer(&mut writer)?;

if self.sqs_splitting {
writer.write_all(b"---\n")?;
MirrordWorkloadQueueRegistry::crd().to_writer(&mut writer)?;
Expand Down Expand Up @@ -562,8 +566,12 @@ impl OperatorClusterRole {
},
// Allow the operator to list+get mirrord policies.
PolicyRule {
// Both namespaced and cluster-wide policies live in the same API group.
api_groups: Some(vec![MirrordPolicy::group(&()).into_owned()]),
resources: Some(vec![MirrordPolicy::plural(&()).into_owned()]),
resources: Some(vec![
MirrordPolicy::plural(&()).into_owned(),
MirrordClusterPolicy::plural(&()).into_owned(),
]),
verbs: vec!["list".to_owned(), "get".to_owned()],
..Default::default()
},
Expand Down
3 changes: 2 additions & 1 deletion tests/src/operator/policies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use std::{collections::BTreeMap, time::Duration};

use kube::Api;
use mirrord_operator::crd::{
label_selector::LabelSelector, BlockedFeature, MirrordPolicy, MirrordPolicySpec,
label_selector::LabelSelector,
policy::{BlockedFeature, MirrordPolicy, MirrordPolicySpec},
};
use rstest::{fixture, rstest};

Expand Down
Loading