Trait Plugin

Source
pub trait Plugin: BasePluginExported + Sized {
    type ConfigType: ConfigSchema;

    const NAME: &'static CStr;
    const PLUGIN_VERSION: &'static CStr;
    const DESCRIPTION: &'static CStr;
    const CONTACT: &'static CStr;

    // Required method
    fn new(
        input: Option<&TablesInput<'_>>,
        config: Self::ConfigType,
    ) -> Result<Self, Error>;

    // Provided methods
    fn set_config(&mut self, _config: Self::ConfigType) -> Result<(), Error> { ... }
    fn get_metrics(&mut self) -> impl IntoIterator<Item = Metric> { ... }
}
Expand description

§A base trait for implementing Falco plugins

There are several constants you need to set to describe the metadata for your plugin, described below. All the constants are C-style strings: you can initialize the fields with c"foo".

For example, a plugin that doesn’t support any capabilities (which is useless and would fail to load, but is a necessary step to building an actually useful plugin) might look like:

use std::ffi::CStr;
use falco_plugin::base::{Metric, Plugin};
use falco_plugin::plugin;
use falco_plugin::FailureReason;
use falco_plugin::tables::TablesInput;

// define the type holding the plugin state
struct NoOpPlugin;

// implement the base::Plugin trait
impl Plugin for NoOpPlugin {
    const NAME: &'static CStr = c"sample-plugin-rs";
    const PLUGIN_VERSION: &'static CStr = c"0.0.1";
    const DESCRIPTION: &'static CStr = c"A sample Falco plugin that does nothing";
    const CONTACT: &'static CStr = c"you@example.com";
    type ConfigType = ();

    fn new(input: Option<&TablesInput>, config: Self::ConfigType)
        -> Result<Self, anyhow::Error> {
        Ok(NoOpPlugin)
    }
}

// generate the actual plugin wrapper code
// note we need to decorate the type name with `#[no_capabilities]` to bypass
// the safeguard against building an invalid plugin
plugin!(#[no_capabilities] NoOpPlugin);

Required Associated Constants§

Source

const NAME: &'static CStr

the name of your plugin, must match the plugin name in the Falco config file

Source

const PLUGIN_VERSION: &'static CStr

the version of your plugin

Source

const DESCRIPTION: &'static CStr

a free-form description of what your plugin does

Source

const CONTACT: &'static CStr

a way to contact you with issues regarding the plugin, be it email or a website

Required Associated Types§

Source

type ConfigType: ConfigSchema

The plugin can be configured in three different ways. In all cases, an instance of the type you specify will be passed to the Plugin::new method.

See https://falco.org/docs/plugins/usage/ for more information about plugin configuration in Falco.

§No configuration

If your plugin does not need any configuration, set the ConfigType to an empty tuple.

§Configuration as a string

If you set the ConfigType to String, your plugin will receive the configuration as a string, read directly from the Falco config file.

§Configuration as JSON

Plugins can also be configured using a JSON object. This will be parsed by the SDK and your plugin will receive a data structure containing all the parsed fields. In order to use JSON configuration, set the ConfigType to Json<T>, where the Json type is provided by this crate and the type T must implement serde::de::DeserializeOwned and [schemars::JsonSchema].

You will also need to provide a JSON schema for the plugin API to validate the configuration.

Please note that you can use the reexports (falco_plugin::serde and falco_plugin::schemars) to ensure you’re using the same version of serde and schemars as the SDK.

Your config struct might look like:

use falco_plugin::schemars::JsonSchema;
use falco_plugin::serde::Deserialize;

#[derive(JsonSchema, Deserialize)]
#[schemars(crate = "falco_plugin::schemars")]
#[serde(crate = "falco_plugin::serde")]
struct MyConfig {
    /* ... */
}

You can use irrefutable patterns in your new and set_config methods to make JSON configs a little more ergonomic:

use std::ffi::CStr;
use anyhow::Error;
use falco_plugin::base::{Json, Metric, Plugin};
use falco_plugin::schemars::JsonSchema;
use falco_plugin::serde::Deserialize;

use falco_plugin::tables::TablesInput;

#[derive(JsonSchema, Deserialize)]
#[schemars(crate = "falco_plugin::schemars")]
#[serde(crate = "falco_plugin::serde")]
struct MyConfig {
    debug: bool,
}

struct MyPlugin;

impl Plugin for MyPlugin {
    // ...

    type ConfigType = Json<MyConfig>;

    fn new(input: Option<&TablesInput>, Json(config): Json<MyConfig>) -> Result<Self, Error> {
    //                                  ^^^^^^^^^^^^
        if config.debug { /* ... */ }

        // ...
    }

    fn set_config(&mut self, Json(config): Json<MyConfig>) -> Result<(), Error> {
    //                       ^^^^^^^^^^^^
        if config.debug { /* ... */ }

        // ...
    }


    // ...
}

Required Methods§

Source

fn new( input: Option<&TablesInput<'_>>, config: Self::ConfigType, ) -> Result<Self, Error>

This method takes a TablesInput instance, which lets you access tables exposed by other plugins (and Falco core).

It should return a new instance of Self

Provided Methods§

Source

fn set_config(&mut self, _config: Self::ConfigType) -> Result<(), Error>

Update the configuration of a running plugin

The default implementation does nothing

Source

fn get_metrics(&mut self) -> impl IntoIterator<Item = Metric>

Return the plugin metrics

Metrics are described by:

Note: The plugin name is prepended to the metric name, so a metric called foo in a plugin called bar will be emitted by the plugin framework as bar.foo.

Note: Metrics aren’t registered in the framework in any way and there is no requirement to report the same metrics on each call to get_metrics. However, it’s probably a good idea to do so, or at least not to change the type of metric or the type of its value from call to call.

There are two general patterns to use when emitting metrics from a plugin:

  1. Predefined metrics
struct MyPlugin {
   // ...
   my_metric: MetricLabel,
}
    fn new(input: Option<&TablesInput>, config: Self::ConfigType)
        -> Result<Self, anyhow::Error> {
        Ok(MyPlugin {
            // ...
            my_metric: MetricLabel::new(c"my_metric", MetricType::Monotonic),
        })
    }

    fn get_metrics(&mut self) -> impl IntoIterator<Item=Metric> {
        [self.my_metric.with_value(MetricValue::U64(10u64))]
    }
  1. Inline metrics
    fn get_metrics(&mut self) -> impl IntoIterator<Item=Metric> {
        [Metric::new(
            MetricLabel::new(c"my_metric", MetricType::Monotonic),
            MetricValue::U64(10u64),
        )]
    }

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§