proxy-wasm / proxy-wasm-rust-sdk

WebAssembly for Proxies (Rust SDK)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Reload Plugin Configuration

antonengelhardt opened this issue · comments

Hey,

i'm loading the plugin configuration initially by implementing the on_configure for the RootContext-Trait and by calling get_plugin_configuration. Then the Struct that implements the RootContext-Trait goes through some states and fetches various things from endpoints such as openid-configuration & jwks. There is a variable in the plugin configuration called reload_interval_in_h that determines when the reloading should take place.

I tried to put the same code, that i have in my on_configure-Function into the on_tick-Function but it seems that it cannot get the config there. Is it impossible to call get_plugin_configuration inside on_tick?

Thanks.

My on_configure-Function (able to retrieve the config):

/// Called when proxy is being configured.
    /// This is where the plugin configuration is loaded and the next state is set.
    fn on_configure(&mut self, _plugin_configuration_size: usize) -> bool {

        info!("Plugin is configuring");

        // Load the configuration from the plugin configuration.
        match self.get_plugin_configuration() {
            Some(config_bytes) => {
                debug!("got plugin configuration");

                // Parse the configuration in a yaml format.
                match serde_yaml::from_slice::<PluginConfiguration>(&config_bytes) {
                    Ok(plugin_config) => {
                        debug!("parsed plugin configuration");

                        // Create AES256 Cipher from base64 encoded key
                        let aes_key = base64engine.decode(&plugin_config.aes_key).unwrap();
                        let cipher = Aes256Gcm::new_from_slice(&aes_key).unwrap();
                        self.cipher = Some(cipher);

                        // Advance to the next state and store the plugin configuration.
                        self.state = OidcRootState::LoadingConfig {
                            plugin_config: Arc::new(plugin_config),
                        };

                        // Tick immediately to load the configuration.
                        // See `on_tick` for more information.
                        self.set_tick_period(Duration::from_millis(1));

                        return true;
                    }
                    Err(e) => warn!("error parsing plugin configuration: {:?}", e),
                }
            }
            None => warn!("no plugin configuration"),
        }

        false
    }

My on_tick-Function:

fn on_tick(&mut self) {
        debug!("tick");

        // See what the current state is.
        match &self.state {
 
          [...]

           OidcRootState::Ready{
                open_id_config: _,
                ..
            }=> {

                // If this state is reached, the plugin was ready and needs to reload the configuration.
                // This is controlled by `reload_interval_in_h` in the plugin configuration.
                // The state is set to `LoadingConfig` and the tick period is set to 1ms to load the configuration.
                // Load the configuration from the plugin configuration.
                match self.get_plugin_configuration() {
                    Some(config_bytes) => {
                        debug!("got plugin configuration : {:?}", config_bytes);

                        // Parse the configuration in a yaml format.
                        match serde_yaml::from_slice::<PluginConfiguration>(&config_bytes) {
                            Ok(plugin_config) => {
                                debug!("parsed plugin configuration: {:?}", plugin_config);

                                // Create AES256 Cipher from base64 encoded key
                                let aes_key = base64engine.decode(&plugin_config.aes_key).unwrap();
                                let cipher = Aes256Gcm::new_from_slice(&aes_key).unwrap();
                                self.cipher = Some(cipher);

                                // Advance to the next state and store the plugin configuration.
                                self.state = OidcRootState::LoadingConfig{
                                    plugin_config: Arc::new(plugin_config),
                                };
                                self.set_tick_period(Duration::from_millis(1));
                            }
                            Err(e) => warn!("error parsing plugin configuration: {:?}", e),
                            }
                        }
                    None => warn!("no plugin configuration"),
                }
            }
        }
    }

Output is:

wasm-oidc-plugin-envoy-1    | [2023-07-13 15:16:18.673][21][warning][wasm] [source/extensions/common/wasm/context.cc:1151] wasm log: no plugin configuration

Correct, plugin configuration is only accessible in the on_configure callback.

And there's no other way of accessing the configuration again after on_configure is done?

No, but you can store it inside plugin during the on_configure callback.

Im doing that, but I'd like to update its contents on a specified interval.

What do you mean "update its contents"? Where is the new configuration?

The configuration is loaded from envoy.yaml. In there a variable can be set that controls how often the configuration is reloaded. Right now, I'm getting the OpenID config and Jwks info but I'd also like to reload the values from envoy.yaml on that interval. I can not invoke on_configure again and get_plugin_configuration only seems to work in that function...

So you're trying to load updated plugin configuration from envoy.yaml?

When a plugin configuration changes in Envoy, a new plugin instance is created and you'll get a new on_configure callback for it. All subsequent requests will also point to it as a parent instead of the old version (while the requests/responses in flight will still refer to the old version).

Also, the configuration is effectively immutable for the lifetime of the plugin instance, so even if you could access it from on_tick, it would be still the exactly same configuration as you original retrieved in on_configure.

Thanks for your reply. All understood

It seems that there is no need to completely restart the envoy instance any more as there is a hot reload feature

Thanks!

AFAICT, Envoy's hot restart is primarily used for binary upgrades, but Envoy supports dynamic configuration without the need to restart or even reload it, either via xDS protocol or from the file system.