Skip to content

Commit

Permalink
Added support for _proxy-filtered flag. (#366)
Browse files Browse the repository at this point in the history
The new flag is an enterprise only flag. The new flag will make sure the command will not appeared on slow log, command command, and other location where we do not want to expose it.
  • Loading branch information
MeirShpilraien authored Oct 16, 2023
1 parent a6156e3 commit 6be84d1
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ commands:
- run:
name: patch macos tests # Avoid AVX with Regex with CircleCI since virtualization layer doesn't support it. Use sed to replace the relevant entry in cargo.toml
command: |
if [[ $(uname -s) == Darwin ]]; then sed -i 's/regex = "1"/regex = { version = "1", features = ["perf", "unicode"] }/g' Cargo.toml; fi
if [[ $(uname -s) == Darwin ]]; then sed -i 's/regex = "1"/regex = { version = "1", features = ["perf", "unicode"], default-features = false }/g' Cargo.toml; fi
cat Cargo.toml
- restore_cache:
keys:
Expand Down
35 changes: 31 additions & 4 deletions redismodule-rs-macros/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ impl From<&RedisCommandFlags> for &'static str {
}
}

#[derive(Debug, Deserialize)]
pub enum RedisEnterpriseCommandFlags {
/// A special enterprise only flag, make sure the commands marked with this flag will not be expose to
/// user via `command` command or on slow log.
ProxyFiltered,
}

impl From<&RedisEnterpriseCommandFlags> for &'static str {
fn from(value: &RedisEnterpriseCommandFlags) -> Self {
match value {
RedisEnterpriseCommandFlags::ProxyFiltered => "_proxy-filtered",
}
}
}

#[derive(Debug, Deserialize)]
pub enum RedisCommandKeySpecFlags {
/// Read-Only. Reads the value of the key, but doesn't necessarily return it.
Expand Down Expand Up @@ -212,6 +227,7 @@ pub struct KeySpecArg {
struct Args {
name: Option<String>,
flags: Vec<RedisCommandFlags>,
enterprise_flags: Option<Vec<RedisEnterpriseCommandFlags>>,
summary: Option<String>,
complexity: Option<String>,
since: Option<String>,
Expand Down Expand Up @@ -240,10 +256,7 @@ pub(crate) fn redis_command(attr: TokenStream, item: TokenStream) -> TokenStream

let original_function_name = func.sig.ident.clone();

let c_function_name = Ident::new(
&format!("_inner_{}", func.sig.ident),
func.sig.ident.span(),
);
let c_function_name = Ident::new(&format!("_inner_{}", func.sig.ident), func.sig.ident.span());

let get_command_info_function_name = Ident::new(
&format!("_inner_get_command_info_{}", func.sig.ident),
Expand All @@ -262,6 +275,19 @@ pub(crate) fn redis_command(attr: TokenStream, item: TokenStream) -> TokenStream
.trim()
.to_owned();
let flags_literal = quote!(#flags_str);
let enterprise_flags_str = args
.enterprise_flags
.map(|v| {
v.into_iter()
.fold(String::new(), |s, v| {
format!("{} {}", s, Into::<&'static str>::into(&v))
})
.trim()
.to_owned()
})
.unwrap_or_default();

let enterprise_flags_literal = quote!(#enterprise_flags_str);
let summary_literal = to_token_stream(args.summary);
let complexity_literal = to_token_stream(args.complexity);
let since_literal = to_token_stream(args.since);
Expand Down Expand Up @@ -362,6 +388,7 @@ pub(crate) fn redis_command(attr: TokenStream, item: TokenStream) -> TokenStream
Ok(redis_module::commands::CommandInfo::new(
#name_literal.to_owned(),
Some(#flags_literal.to_owned()),
Some(#enterprise_flags_literal.to_owned()),
#summary_literal,
#complexity_literal,
#since_literal,
Expand Down
3 changes: 2 additions & 1 deletion redismodule-rs-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ mod redis_value;
/// This proc macro allow to specify that the follow function is a Redis command.
/// The macro accept the following arguments that discribe the command properties:
/// * name (optional) - The command name. in case not given, the function name will be taken.
/// * flags - An array of `RedisCommandFlags`.
/// * flags - An array of [`command::RedisCommandFlags`].
/// * enterprise_flags - An array of [`command::RedisEnterpriseCommandFlags`].
/// * summary (optional) - Command summary
/// * complexity (optional) - Command compexity
/// * since (optional) - At which module version the command was first introduce
Expand Down
16 changes: 9 additions & 7 deletions src/context/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ type CommandCallback =
pub struct CommandInfo {
name: String,
flags: Option<String>,
enterprise_flags: Option<String>,
summary: Option<String>,
complexity: Option<String>,
since: Option<String>,
Expand All @@ -328,6 +329,7 @@ impl CommandInfo {
pub fn new(
name: String,
flags: Option<String>,
enterprise_flags: Option<String>,
summary: Option<String>,
complexity: Option<String>,
since: Option<String>,
Expand All @@ -339,6 +341,7 @@ impl CommandInfo {
CommandInfo {
name,
flags,
enterprise_flags,
summary,
complexity,
since,
Expand Down Expand Up @@ -368,16 +371,15 @@ api! {[
],
/// Register all the commands located on `COMMNADS_LIST`.
fn register_commands_internal(ctx: &Context) -> Result<(), RedisError> {
let is_enterprise = ctx.is_enterprise();
COMMANDS_LIST.iter().try_for_each(|command| {
let command_info = command()?;
let name: CString = CString::new(command_info.name.as_str()).unwrap();
let flags = CString::new(
command_info
.flags
.as_deref()
.unwrap_or(""),
)
.unwrap();
let mut flags = command_info.flags.as_deref().unwrap_or("").to_owned();
if is_enterprise {
flags = format!("{flags} {}", command_info.enterprise_flags.as_deref().unwrap_or("")).trim().to_owned();
}
let flags = CString::new(flags).map_err(|e| RedisError::String(e.to_string()))?;

if unsafe {
RedisModule_CreateCommand(
Expand Down
18 changes: 18 additions & 0 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,24 @@ impl Context {
unsafe { RedisModule_AvoidReplicaTraffic() == 1 }
}
);

/// Return [Ok(true)] is the current Redis deployment is enterprise, otherwise [Ok(false)].
/// Return error in case it was not possible to determind the deployment.
fn is_enterprise_internal(&self) -> Result<bool, RedisError> {
let info_res = self.call("info", &["server"])?;
match info_res {
RedisValue::BulkRedisString(res) => Ok(res.try_as_str()?.contains("rlec_version:")),
_ => Err(RedisError::Str("Mismatch call reply type")),
}
}

/// Return `true` is the current Redis deployment is enterprise, otherwise `false`.
pub fn is_enterprise(&self) -> bool {
self.is_enterprise_internal().unwrap_or_else(|e| {
log::error!("Failed getting deployment type, assuming oss. Error: {e}.");
false
})
}
}

extern "C" fn post_notification_job_free_callback<F: FnOnce(&Context)>(pd: *mut c_void) {
Expand Down

0 comments on commit 6be84d1

Please sign in to comment.