Skip to main content

Transform

Trait Transform 

Source
pub trait Transform: Send + Sync {
    // Provided methods
    fn transform_host(
        &self,
        host: &Host,
        _options: Option<&TransformFunctionOptions>,
    ) -> Host { ... }
    fn transform_group(
        &self,
        group: &Group,
        _options: Option<&TransformFunctionOptions>,
    ) -> Group { ... }
    fn transform_defaults(
        &self,
        defaults: &Defaults,
        _options: Option<&TransformFunctionOptions>,
    ) -> Defaults { ... }
}
Expand description

A trait for implementing custom transformation logic on inventory entities.

The Transform trait provides a flexible mechanism to modify hosts, groups, and defaults in an inventory based on custom logic, external configuration, or runtime conditions. Implementations of this trait can be wrapped in a TransformFunction and applied to an inventory to dynamically alter entity properties without modifying the underlying data.

All methods in this trait have default implementations that return clones of the input entities unchanged. Implementors only need to override the methods for entity types they wish to transform.

§Thread Safety

Implementations must be Send + Sync to allow safe sharing across threads. The inventory system uses Arc internally to share transform functions, so all transform logic must be thread-safe.

§Transform Methods

The trait provides three transformation methods, one for each inventory entity type:

  • transform_host - Transforms individual host configurations
  • transform_group - Transforms group configurations
  • transform_defaults - Transforms inventory-wide defaults

Each method receives a reference to the entity being transformed and optional configuration through TransformFunctionOptions. The methods should return a new instance of the entity with the desired modifications applied.

§When Transforms Are Applied

Transforms are applied lazily when accessing inventory entities:

  • When calling Inventory::hosts() and accessing individual hosts
  • When calling Inventory::groups() and accessing individual groups
  • When calling Inventory::defaults()
  • During host resolution via Inventory::resolve_host()

Results are cached for hosts and groups to improve performance on subsequent accesses. Resolved hosts and connection parameters are also cached by Inventory. Defaults are transformed lazily on each Inventory::defaults() call and are not stored in a dedicated cache.

§Transform Options

The optional TransformFunctionOptions parameter provides a way to pass configuration data to the transform function at runtime. This allows for flexible, data-driven transformations without hardcoding values in the transform implementation.

Options are stored as JSON values and can contain any structured data needed by the transform logic. Access the options using the get() method and JSON value accessors.

§Examples

§Basic Host Transform

struct PortTransform {
    default_port: u16,
}

impl Transform for PortTransform {
    fn transform_host(&self, host: &Host, _options: Option<&TransformFunctionOptions>) -> Host {
        // Apply default port if host doesn't have one
        if host.port().is_none() {
            host.to_builder()
                .port(self.default_port)
                .build()
        } else {
            host.clone()
        }
    }
}

let transform = TransformFunction::new_full(PortTransform { default_port: 2222 });

§Transform Using Options

struct PrefixTransform;

impl Transform for PrefixTransform {
    fn transform_host(&self, host: &Host, options: Option<&TransformFunctionOptions>) -> Host {
        // Get prefix from options
        let prefix = options
            .and_then(|opts| opts.get("hostname_prefix"))
            .and_then(|v| v.as_str())
            .unwrap_or("");

        if !prefix.is_empty() {
            if let Some(hostname) = host.hostname() {
                return host.to_builder()
                    .hostname(format!("{}{}", prefix, hostname))
                    .build();
            }
        }
        host.clone()
    }
}

let transform = TransformFunction::new_full(PrefixTransform);
let options = TransformFunctionOptions::new(
    serde_json::json!({"hostname_prefix": "prod-"})
);

§Multi-Entity Transform

struct EnvironmentTransform {
    environment: String,
}

impl Transform for EnvironmentTransform {
    fn transform_host(&self, host: &Host, _options: Option<&TransformFunctionOptions>) -> Host {
        // Add environment tag to hostname
        if let Some(hostname) = host.hostname() {
            host.to_builder()
                .hostname(format!("{}.{}", hostname, self.environment))
                .build()
        } else {
            host.clone()
        }
    }

    fn transform_group(&self, group: &Group, _options: Option<&TransformFunctionOptions>) -> Group {
        // Apply environment-specific group settings
        if self.environment == "prod" {
            // Production groups might need different settings
            group.to_builder()
                .port(443)
                .build()
        } else {
            group.clone()
        }
    }

    fn transform_defaults(&self, defaults: &Defaults, _options: Option<&TransformFunctionOptions>) -> Defaults {
        // Apply environment-specific defaults
        defaults.to_builder()
            .username(format!("{}-user", self.environment))
            .build()
    }
}

let transform = TransformFunction::new_full(EnvironmentTransform {
    environment: "prod".to_string(),
});

§IP Address Mapping Transform

struct IpMappingTransform;

impl Transform for IpMappingTransform {
    fn transform_host(&self, host: &Host, options: Option<&TransformFunctionOptions>) -> Host {
        // Get IP mapping from options
        let mapping = options
            .and_then(|opts| opts.get("ip_map"))
            .and_then(|v| v.as_object());

        let Some(mapping) = mapping else {
            return host.clone();
        };

        let mut builder = host.to_builder();

        // Map hostname if it exists in the mapping
        if let Some(hostname) = host.hostname() {
            if let Some(mapped) = mapping.get(hostname).and_then(|v| v.as_str()) {
                builder = builder.hostname(mapped);
            }
        }

        builder.build()
    }
}

let transform = TransformFunction::new_full(IpMappingTransform);
let options = TransformFunctionOptions::new(serde_json::json!({
    "ip_map": {
        "10-0-0-1": "10.0.0.1",
        "10-0-0-2": "10.0.0.2"
    }
}));

Provided Methods§

Source

fn transform_host( &self, host: &Host, _options: Option<&TransformFunctionOptions>, ) -> Host

Transforms a host entity.

This method is called when a host is accessed through the inventory’s host view or during host resolution. The default implementation returns a clone of the input host unchanged.

§Parameters
  • host - A reference to the host being transformed
  • _options - Optional configuration data for the transform
§Returns

Returns a new Host instance with the desired transformations applied.

Source

fn transform_group( &self, group: &Group, _options: Option<&TransformFunctionOptions>, ) -> Group

Transforms a group entity.

This method is called when a group is accessed through the inventory’s group view. The default implementation returns a clone of the input group unchanged.

§Parameters
  • group - A reference to the group being transformed
  • _options - Optional configuration data for the transform
§Returns

Returns a new Group instance with the desired transformations applied.

Source

fn transform_defaults( &self, defaults: &Defaults, _options: Option<&TransformFunctionOptions>, ) -> Defaults

Transforms the inventory defaults.

This method is called when defaults are accessed through Inventory::defaults(). The default implementation returns a clone of the input defaults unchanged.

§Parameters
  • defaults - A reference to the defaults being transformed
  • _options - Optional configuration data for the transform
§Returns

Returns a new Defaults instance with the desired transformations applied.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§