re-uploading work
This commit is contained in:
403
crates/core-timer-sensor/README.md
Normal file
403
crates/core-timer-sensor/README.md
Normal file
@@ -0,0 +1,403 @@
|
||||
# Attune Timer Sensor
|
||||
|
||||
A standalone sensor daemon for the Attune automation platform that monitors timer-based triggers and emits events. This sensor manages multiple concurrent timer schedules based on active rules.
|
||||
|
||||
## Overview
|
||||
|
||||
The timer sensor is a lightweight, event-driven process that:
|
||||
|
||||
- Listens for rule lifecycle events via RabbitMQ
|
||||
- Manages per-rule timer tasks dynamically
|
||||
- Emits events to the Attune API when timers fire
|
||||
- Supports interval-based, cron-based, and datetime-based timers
|
||||
- Authenticates using service account tokens
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Timer Sensor Process │
|
||||
│ │
|
||||
│ ┌────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Rule Lifecycle │───▶│ Timer Manager │ │
|
||||
│ │ Listener │ │ │ │
|
||||
│ │ (RabbitMQ) │ │ ┌──────────────┐ │ │
|
||||
│ └────────────────┘ │ │ Rule 1 Timer │ │ │
|
||||
│ │ ├──────────────┤ │ │
|
||||
│ │ │ Rule 2 Timer │ │───┐ │
|
||||
│ │ ├──────────────┤ │ │ │
|
||||
│ │ │ Rule 3 Timer │ │ │ │
|
||||
│ │ └──────────────┘ │ │ │
|
||||
│ └──────────────────┘ │ │
|
||||
│ │ │
|
||||
│ ┌────────────────┐ │ │
|
||||
│ │ API Client │◀──────────────────────────┘ │
|
||||
│ │ (Create Events)│ │
|
||||
│ └────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│ ▲
|
||||
│ Events │ Rule Lifecycle
|
||||
▼ │ Messages
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Attune API │ │ RabbitMQ │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Per-Rule Timers**: Each rule gets its own independent timer task
|
||||
- **Dynamic Management**: Timers start/stop automatically based on rule lifecycle
|
||||
- **Multiple Timer Types**:
|
||||
- **Interval**: Fire every N seconds/minutes/hours/days
|
||||
- **Cron**: Fire based on cron expression (planned)
|
||||
- **DateTime**: Fire at a specific date/time
|
||||
- **Resilient**: Retries event creation with exponential backoff
|
||||
- **Secure**: Token-based authentication with trigger type restrictions
|
||||
- **Observable**: Structured JSON logging for monitoring
|
||||
|
||||
## Installation
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
cargo build --release --package core-timer-sensor
|
||||
sudo cp target/release/attune-core-timer-sensor /usr/local/bin/
|
||||
```
|
||||
|
||||
### Using Cargo Install
|
||||
|
||||
```bash
|
||||
cargo install --path crates/core-timer-sensor
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The sensor requires the following environment variables:
|
||||
|
||||
| Variable | Required | Description | Example |
|
||||
|----------|----------|-------------|---------|
|
||||
| `ATTUNE_API_URL` | Yes | Base URL of the Attune API | `http://localhost:8080` |
|
||||
| `ATTUNE_API_TOKEN` | Yes | Service account token | `eyJhbGci...` |
|
||||
| `ATTUNE_SENSOR_REF` | Yes | Sensor reference (must be `core.timer`) | `core.timer` |
|
||||
| `ATTUNE_MQ_URL` | Yes | RabbitMQ connection URL | `amqp://localhost:5672` |
|
||||
| `ATTUNE_MQ_EXCHANGE` | No | RabbitMQ exchange name | `attune` (default) |
|
||||
| `ATTUNE_LOG_LEVEL` | No | Logging verbosity | `info` (default) |
|
||||
|
||||
### Example: Environment Variables
|
||||
|
||||
```bash
|
||||
export ATTUNE_API_URL="http://localhost:8080"
|
||||
export ATTUNE_API_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
export ATTUNE_SENSOR_REF="core.timer"
|
||||
export ATTUNE_MQ_URL="amqp://localhost:5672"
|
||||
export ATTUNE_LOG_LEVEL="info"
|
||||
|
||||
attune-core-timer-sensor
|
||||
```
|
||||
|
||||
### Example: stdin Configuration
|
||||
|
||||
```bash
|
||||
echo '{
|
||||
"api_url": "http://localhost:8080",
|
||||
"api_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"sensor_ref": "core.timer",
|
||||
"mq_url": "amqp://localhost:5672",
|
||||
"mq_exchange": "attune",
|
||||
"log_level": "info"
|
||||
}' | attune-core-timer-sensor --stdin-config
|
||||
```
|
||||
|
||||
## Service Account Setup
|
||||
|
||||
Before running the sensor, you need to create a service account with the appropriate permissions:
|
||||
|
||||
```bash
|
||||
# Create service account (requires admin token)
|
||||
curl -X POST http://localhost:8080/service-accounts \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "sensor:core.timer",
|
||||
"scope": "sensor",
|
||||
"description": "Timer sensor for interval-based triggers",
|
||||
"ttl_hours": 72,
|
||||
"metadata": {
|
||||
"trigger_types": ["core.timer"]
|
||||
}
|
||||
}'
|
||||
|
||||
# Response will include the token (save this - it's only shown once!)
|
||||
{
|
||||
"identity_id": 123,
|
||||
"name": "sensor:core.timer",
|
||||
"scope": "sensor",
|
||||
"token": "eyJhbGci...", # Use this as ATTUNE_API_TOKEN
|
||||
"expires_at": "2025-01-30T12:34:56Z" # 72 hours from now
|
||||
}
|
||||
```
|
||||
|
||||
**Important**:
|
||||
- The token is only displayed once. Store it securely!
|
||||
- Sensor tokens expire after 24-72 hours and must be rotated
|
||||
- Plan to rotate the token before expiration (set up monitoring/alerts)
|
||||
|
||||
## Timer Configuration
|
||||
|
||||
Rules using the `core.timer` trigger must provide configuration in `trigger_params`:
|
||||
|
||||
### Interval Timer
|
||||
|
||||
Fires every N units of time:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "interval",
|
||||
"interval": 30,
|
||||
"unit": "seconds" // "seconds", "minutes", "hours", "days"
|
||||
}
|
||||
```
|
||||
|
||||
Examples:
|
||||
- Every 5 seconds: `{"type": "interval", "interval": 5, "unit": "seconds"}`
|
||||
- Every 10 minutes: `{"type": "interval", "interval": 10, "unit": "minutes"}`
|
||||
- Every 1 hour: `{"type": "interval", "interval": 1, "unit": "hours"}`
|
||||
- Every 1 day: `{"type": "interval", "interval": 1, "unit": "days"}`
|
||||
|
||||
### DateTime Timer
|
||||
|
||||
Fires at a specific date/time (one-time):
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "date_time",
|
||||
"fire_at": "2025-01-27T15:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Cron Timer (Planned)
|
||||
|
||||
Fires based on cron expression:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "cron",
|
||||
"expression": "0 0 * * *" // Daily at midnight
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: Cron timers are not yet implemented.
|
||||
|
||||
## Running the Sensor
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Terminal 1: Start dependencies
|
||||
docker-compose up -d postgres rabbitmq
|
||||
|
||||
# Terminal 2: Start API
|
||||
cd crates/api
|
||||
cargo run
|
||||
|
||||
# Terminal 3: Start sensor
|
||||
export ATTUNE_API_URL="http://localhost:8080"
|
||||
export ATTUNE_API_TOKEN="your_sensor_token_here"
|
||||
export ATTUNE_SENSOR_REF="core.timer"
|
||||
export ATTUNE_MQ_URL="amqp://localhost:5672"
|
||||
|
||||
cargo run --package core-timer-sensor
|
||||
```
|
||||
|
||||
### Production (systemd)
|
||||
|
||||
Create a systemd service file at `/etc/systemd/system/attune-core-timer-sensor.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Attune Timer Sensor
|
||||
After=network.target rabbitmq-server.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=attune
|
||||
WorkingDirectory=/opt/attune
|
||||
ExecStart=/usr/local/bin/attune-core-timer-sensor
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
# Environment variables
|
||||
Environment="ATTUNE_API_URL=https://attune.example.com"
|
||||
Environment="ATTUNE_SENSOR_REF=core.timer"
|
||||
Environment="ATTUNE_MQ_URL=amqps://rabbitmq.example.com:5671"
|
||||
Environment="ATTUNE_LOG_LEVEL=info"
|
||||
|
||||
# Load token from file
|
||||
EnvironmentFile=/etc/attune/sensor-timer.env
|
||||
|
||||
# Security
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Create `/etc/attune/sensor-timer.env`:
|
||||
|
||||
```bash
|
||||
ATTUNE_API_TOKEN=eyJhbGci...
|
||||
```
|
||||
|
||||
Enable and start:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable attune-core-timer-sensor
|
||||
sudo systemctl start attune-core-timer-sensor
|
||||
sudo systemctl status attune-core-timer-sensor
|
||||
```
|
||||
|
||||
**Token Rotation:**
|
||||
|
||||
Sensor tokens expire after 24-72 hours. To rotate:
|
||||
|
||||
```bash
|
||||
# 1. Create new service account token (via API)
|
||||
# 2. Update /etc/attune/sensor-timer.env with new token
|
||||
sudo nano /etc/attune/sensor-timer.env
|
||||
|
||||
# 3. Restart sensor
|
||||
sudo systemctl restart attune-core-timer-sensor
|
||||
```
|
||||
|
||||
Set up a cron job or monitoring alert to remind you to rotate tokens every 72 hours.
|
||||
|
||||
View logs:
|
||||
|
||||
```bash
|
||||
sudo journalctl -u attune-core-timer-sensor -f
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Logs
|
||||
|
||||
The sensor outputs structured JSON logs:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-01-27T12:34:56Z",
|
||||
"level": "info",
|
||||
"message": "Timer fired for rule 123, created event 456",
|
||||
"rule_id": 123,
|
||||
"event_id": 456
|
||||
}
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
The sensor verifies API connectivity on startup. Monitor the logs for:
|
||||
|
||||
- `"API connectivity verified"` - Sensor connected successfully
|
||||
- `"Timer started for rule"` - Timer activated for a rule
|
||||
- `"Timer fired for rule"` - Event created by timer
|
||||
- `"Failed to create event"` - Event creation error (check token/permissions)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Invalid sensor_ref: expected 'core.timer'"
|
||||
|
||||
The `ATTUNE_SENSOR_REF` must be exactly `core.timer`. This sensor only handles timer triggers.
|
||||
|
||||
### "Failed to connect to Attune API"
|
||||
|
||||
- Verify `ATTUNE_API_URL` is correct and reachable
|
||||
- Check that the API service is running
|
||||
- Ensure no firewall blocking the connection
|
||||
|
||||
### "Insufficient permissions to create event for trigger type 'core.timer'"
|
||||
|
||||
The service account token doesn't have permission to create timer events. Ensure the token's metadata includes `"trigger_types": ["core.timer"]`.
|
||||
|
||||
### "Failed to connect to RabbitMQ"
|
||||
|
||||
- Verify `ATTUNE_MQ_URL` is correct
|
||||
- Check that RabbitMQ is running
|
||||
- Ensure credentials are correct in the URL
|
||||
|
||||
### "Token expired"
|
||||
|
||||
The service account token has exceeded its TTL (24-72 hours). This is expected behavior.
|
||||
|
||||
**Solution:**
|
||||
1. Create a new service account token via API
|
||||
2. Update `ATTUNE_API_TOKEN` environment variable
|
||||
3. Restart the sensor
|
||||
|
||||
**Prevention:**
|
||||
- Set up monitoring to alert 6 hours before token expiration
|
||||
- Plan regular token rotation (every 72 hours maximum)
|
||||
|
||||
### Timer not firing
|
||||
|
||||
1. Check that the rule is enabled
|
||||
2. Verify the rule's `trigger_type` is `core.timer`
|
||||
3. Check the sensor logs for "Timer started for rule"
|
||||
4. Ensure `trigger_params` is valid JSON matching the timer config format
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
cargo test --package core-timer-sensor
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Debug build
|
||||
cargo build --package core-timer-sensor
|
||||
|
||||
# Release build
|
||||
cargo build --release --package core-timer-sensor
|
||||
```
|
||||
|
||||
### Code Structure
|
||||
|
||||
```
|
||||
crates/core-timer-sensor/
|
||||
├── src/
|
||||
│ ├── main.rs # Entry point, initialization
|
||||
│ ├── config.rs # Configuration loading (env/stdin)
|
||||
│ ├── api_client.rs # Attune API communication
|
||||
│ ├── timer_manager.rs # Per-rule timer task management
|
||||
│ ├── rule_listener.rs # RabbitMQ message consumer
|
||||
│ └── types.rs # Shared types and enums
|
||||
├── Cargo.toml
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
When adding new timer types:
|
||||
|
||||
1. Add variant to `TimerConfig` enum in `types.rs`
|
||||
2. Implement spawn logic in `timer_manager.rs`
|
||||
3. Add tests for the new timer type
|
||||
4. Update this README with examples
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Sensor Interface Specification](../../docs/sensor-interface.md)
|
||||
- [Service Accounts Documentation](../../docs/service-accounts.md)
|
||||
- [Sensor Authentication Overview](../../docs/sensor-authentication-overview.md)
|
||||
Reference in New Issue
Block a user