Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
amousset committed Oct 18, 2022
1 parent 6e6c4e8 commit 3eb4e0f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 5 deletions.
2 changes: 1 addition & 1 deletion policies/resource-types/directory/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= Template
# Template

Template resource type.

Expand Down
2 changes: 1 addition & 1 deletion policies/resource-types/template/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
= Directory
# Directory

Directory resource type.
2 changes: 2 additions & 0 deletions policies/rudderc/docs/examples/ntp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ resources:
enforce: "true"
reporting:
enabled: true
files:
- ntp.conf.tpl
82 changes: 79 additions & 3 deletions policies/rudderc/src/ir/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

use anyhow::{bail, Error};
use std::collections::HashMap;
use std::fmt;
use std::path::PathBuf;
use std::str::FromStr;

use serde::{de, Deserialize, Deserializer, Serialize};
Expand Down Expand Up @@ -64,9 +66,28 @@ pub struct Policy {
pub id: Id,
pub name: String,
pub version: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub documentation: Option<String>,
pub resources: Vec<Resource>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub parameters: Vec<Parameter>,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub files: Vec<PathBuf>,
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Parameter {
id: Id,
name: String,
description: Option<String>,
// FIXME represent as constraint?
may_be_empty: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand All @@ -78,7 +99,7 @@ pub enum Resource {

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BlockResource {
pub condition: String,
pub condition: ConditionExpr,
pub name: String,
pub params: HashMap<String, String>,
#[serde(rename = "type")]
Expand All @@ -95,7 +116,6 @@ pub struct LeafResource {
pub params: HashMap<String, String>,
#[serde(rename = "type")]
pub resource_type: String,
// contains either states or resources
pub states: Vec<State>,
pub id: Id,
pub reporting: Option<ReportingPolicy>,
Expand All @@ -105,7 +125,7 @@ pub struct LeafResource {
pub struct State {
// TODO specific type with custom deserializer that check validity
// class regex or variables
pub condition: String,
pub condition: ConditionExpr,
pub id: Id,
pub meta: Value,
pub name: String,
Expand Down Expand Up @@ -150,3 +170,59 @@ impl Default for ReportingCompute {
ReportingCompute::Weighted
}
}

/// Valid condition expression
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
#[serde(transparent)]
pub struct ConditionExpr {
inner: String,
}

impl AsRef<String> for ConditionExpr {
fn as_ref(&self) -> &String {
&self.inner
}
}

impl fmt::Display for ConditionExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.inner)
}
}

impl From<ConditionExpr> for String {
fn from(c: ConditionExpr) -> Self {
c.inner
}
}

impl FromStr for ConditionExpr {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
fn valid_char(c: char) -> bool {
// Ideally, we could parse and validate condition expressions.
// For now, let's only check for disallowed chars instead.
let valid_chars = ['"', '$', '{', '}', '|', '&', ' '];
c.is_ascii_alphanumeric() || valid_chars.contains(&c)
}

if s.chars().all(valid_char) {
Ok(ConditionExpr {
inner: s.to_string(),
})
} else {
bail!("Invalid id: {}", s)
}
}
}

impl<'de> Deserialize<'de> for ConditionExpr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(de::Error::custom)
}
}

0 comments on commit 3eb4e0f

Please sign in to comment.