This directory contains examples of plugins for Damon that extend its functionality.
Plugins in Damon are Go shared libraries (.so files) that implement the provider interface. They allow you to extend Damon's functionality without modifying the core codebase.
Warning
Using Go plugins has limitations for production environments due to version compatibility issues. For production use, consider submitting a pull request to include your provider directly in the Damon codebase. The plugin feature is provided for development and testing when you don't want to modify the main repository.
For plugins to work properly with Damon:
- The Go version used to build the plugin MUST match the Go version used to build Damon
- The plugin must be built on the same operating system as where Damon will run
- The import paths in your plugin must match the import paths in Damon
If these requirements aren't met, you'll receive errors when Damon tries to load the plugin.
This example plugin sends Slack notifications whenever specific Nomad events occur.
To build the plugin:
# Ensure you use the exact same Go version used to build Damon
go build -buildmode=plugin -o slack.so ./slack/plugin.go- Place the compiled
.sofile in a directory - Configure Damon to look for plugins in that directory:
[plugins]
directory = "/path/to/plugins"- Start Damon, and it will automatically load and register your plugin
Once loaded, configure the plugin like any other provider:
[provider.slack]
type = "slack" # This must match what your plugin registers as
webhook_url = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"
channel = "#nomad-events"
username = "Damon Bot"
topics = { "Job" = "*", "Deployment" = "*" }
event_types = ["JobRegistered", "DeploymentFailed"] # Optional filterA Damon plugin must implement the following:
- Export a
Registerfunction that registers your provider with Damon's registry - Implement the Provider interface
All providers must implement this interface:
type Provider interface {
// Name returns the name of the provider
Name() string
// OnEvent executes the provider logic on an event stream event
OnEvent(event *api.Event)
// Topics returns the topics required by the event stream provider
Topics() map[api.Topic][]string
// Close performs any cleanup needed when shutting down
Close() error
}Here's a simple template to get you started:
package main
import (
"context"
"log/slog"
"github.com/hashicorp/nomad/api"
"github.com/knadh/koanf/v2"
"github.com/thunderbottom/damon/internal/interfaces"
"github.com/thunderbottom/damon/provider"
)
// Register is the entry point for the plugin
func Register(registry *provider.Registry) error {
return registry.Register("yourprovider", New)
}
// YourProvider implements the Provider interface
type YourProvider struct {
// Your provider fields here
logger *slog.Logger
name string
}
// New creates a new instance of your provider
func New(
ctx context.Context,
logger *slog.Logger,
client interfaces.NomadClient,
cache interfaces.CacheClient,
config *koanf.Koanf,
) (interfaces.Provider, error) {
// Initialize your provider
return &YourProvider{
logger: logger,
name: config.String("name"),
}, nil
}
// Name returns the provider name
func (p *YourProvider) Name() string {
return p.name
}
// OnEvent handles Nomad events
func (p *YourProvider) OnEvent(event *api.Event) {
// Handle the event
}
// Topics returns what event topics to subscribe to
func (p *YourProvider) Topics() map[api.Topic][]string {
return map[api.Topic][]string{
api.TopicJob: {"*"},
}
}
// Close performs cleanup
func (p *YourProvider) Close() error {
return nil
}The included Slack provider is a real-world example that sends Nomad event notifications to Slack channels.
The Slack provider demonstrates several important plugin concepts:
- Reading configuration values from TOML
- Processing different Nomad event types
- Formatting structured messages for an external API
- Error handling and logging
A well-organized provider typically has:
- Configuration Structure: For provider-specific settings
- Event Handlers: Methods to process different types of events
- External API Integration: Code to call external services
- Helper Methods: Utility functions for common tasks
When creating plugins that integrate with external systems:
- Use appropriate error handling for network operations
- Consider retry logic for transient failures
- Implement proper authentication with API keys or tokens
- Format messages appropriately for the target system
Here are some ideas for custom plugins you could build:
Send email alerts for important Nomad events:
// EmailProvider sends email notifications for Nomad events
type EmailProvider struct {
logger *slog.Logger
name string
smtpConfig *SMTPConfig
topics map[api.Topic][]string
}Send Nomad event metrics to monitoring systems:
// MetricsProvider sends event metrics to Prometheus, StatsD, etc.
type MetricsProvider struct {
logger *slog.Logger
name string
client MetricsClient
}Forward Nomad events to arbitrary HTTP endpoints:
// WebhookProvider forwards events to configured HTTP endpoints
type WebhookProvider struct {
logger *slog.Logger
name string
endpoints []string
client *http.Client
}When developing plugins for Damon:
- Validate Configuration: Check all required configuration values at startup
- Handle Errors Gracefully: Log errors but try to continue operating
- Clean Up Resources: Properly close connections in the
Close()method - Maintain Compatibility: Follow Damon's versioning for interface changes
- Efficient Event Processing: Only process events your plugin cares about
- Proper Logging: Use structured logging with appropriate log levels
- Security: Handle credentials securely, never log sensitive information
If you're having trouble with a plugin:
- Build with debug information:
go build -buildmode=plugin -gcflags="all=-N -l" -o myplugin.so - Run Damon with higher log level:
DAMON_APP__LOG_LEVEL=DEBUG ./damon - Check for version mismatches between Go used to build Damon and the plugin
- Verify the plugin is in the correct directory as specified in config
- Test your plugin's logic separately before integration with Damon
If you've developed a useful plugin, consider contributing it to the main Damon repository:
- Create a new provider directory in
provider/yourprovider/ - Implement the provider interface fully
- Add tests in
provider/yourprovider/yourprovider_test.go - Add documentation in
provider/yourprovider/README.md - Submit a pull request to the Damon repository