Skip to content

Commit

Permalink
add templates and static monitors
Browse files Browse the repository at this point in the history
  • Loading branch information
BigBoot committed Jan 8, 2024
1 parent eb539ec commit 4553975
Show file tree
Hide file tree
Showing 13 changed files with 323 additions and 63 deletions.
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
target
config.toml
docker.sock
docker.sock
monitors
37 changes: 37 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Make Connection timeout configurable [`AUTOKUMA__KUMA__CONNECT_TIMEOUT`]
- Make Call timeout configurable [`AUTOKUMA__KUMA__CALL_TIMEOUT`]
- Allow defining default settings [`AUTOKUMA__KUMA__DEFAULT_SETTINGS`]
- Add templates for setting values
- Ability to load "static" monitors from a directory [`AUTOKUMA__STATIC_MONITORS`]
- Ability to disable docker intergration [`AUTOKUMA__DOCKER__ENABLED`] (useful in combination with `AUTOKUMA__STATIC_MONITORS`)


### Changed
- Increase default timeout for calls and connecting to 5s

### Fixed
- Fix typo in env variable: AUTOKUMA__DOCKER__LABEL_PREFOX -> AUTOKUMA__DOCKER__LABEL_PREFIX

## [0.1.1] - 2024-01-07

### Added
- Ability to parse nested structs from container labels (required for notification_id_list)

### Changed
- Improve error handling

## [0.1.0] - 2024-01-06

### Added
- First release

11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ confique = { version = "0.2.5", default-features = false, features = ["toml"] }
cute_custom_default = { version = "2.1.0" }
derivative = { version = "2.2.0" }
futures-util = { version = "0.3.30" }
humantime-serde = { version = "1.1.1" }
itertools = { version = "0.12.0" }
log = { version = "0.4.20" }
pretty_env_logger = { version = "0.5.0" }
Expand Down
71 changes: 50 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,22 @@ services:
image: ghcr.io/bigboot/autokuma:latest
restart: unless-stopped
environment:
- AUTOKUMA__KUMA__URL=http://localhost:3001
# - AUTOKUMA__KUMA__USERNAME=<username>
# - AUTOKUMA__KUMA__PASSWORD=<password>
# - AUTOKUMA__KUMA__MFA_TOKEN=<token>
# - AUTOKUMA__KUMA__HEADERS="<header1_key>=<header1_value>,<header2_key>=<header2_value>,..."
# - AUTOKUMA__KUMA__TAG_NAME=AutoKuma
# - AUTOKUMA__KUMA__TAG_COLOR=#42C0FB
# - AUTOKUMA__DOCKER__SOCKET=/var/run/docker.sock
# - AUTOKUMA__DOCKER__LABEL_PREFIX=kuma
AUTOKUMA__KUMA__URL: http://localhost:3001
# AUTOKUMA__KUMA__USERNAME: <username>
# AUTOKUMA__KUMA__PASSWORD: <password>
# AUTOKUMA__KUMA__MFA_TOKEN: <token>
# AUTOKUMA__KUMA__HEADERS: "<header1_key>=<header1_value>,<header2_key>=<header2_value>,..."
# AUTOKUMA__KUMA__TAG_NAME: AutoKuma
# AUTOKUMA__KUMA__TAG_COLOR: "#42C0FB"
# AUTOKUMA__KUMA__CALL_TIMEOUT: 5s
# AUTOKUMA__KUMA__CONNECT_TIMEOUT: 5s
# AUTOKUMA__KUMA__DEFAULT_SETTINGS: >-
# docker.docker_container: {{container_name}}
# http.max_redirects: 10
# *.max_retries: 3
# AUTOKUMA__DOCKER__SOCKET: /var/run/docker.sock
# AUTOKUMA__DOCKER__LABEL_PREFIX: kuma

volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
Expand All @@ -44,17 +51,21 @@ services:
AutoKuma can be configured using the following environment variables:
| Variable | Description |
|----------------------------------|------------------------------------------------------------------------------|
| `AUTOKUMA__KUMA__URL` | The url AutoKuma should use to connect to Uptime Kuma |
| `AUTOKUMA__KUMA__USERNAME` | The username for logging into Uptime Kuma (required unless auth is disabled) |
| `AUTOKUMA__KUMA__PASSWORD` | The password for logging into Uptime Kuma (required unless auth is disabled) |
| `AUTOKUMA__KUMA__MFA_TOKEN` | The MFA token for logging into Uptime Kuma (required if MFA is enabled) |
| `AUTOKUMA__KUMA__HEADERS` | List of HTTP headers used when connecting to Uptime Kuma |
| `AUTOKUMA__KUMA__TAG_NAME` | The name of the AutoKuma tag, used to track managed containers |
| `AUTOKUMA__KUMA__TAG_COLOR` | The color of the AutoKuma tag |
| `AUTOKUMA__DOCKER__SOCKET` | Path to the Docker socket |
| `AUTOKUMA__DOCKER__LABEL_PREFIX` | Prefix used when scanning for container labels |
| Variable | Description |
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| `AUTOKUMA__STATIC_MONITORS` | The path to the folder in which AutoKuma will search for static Monitor definitions |
| `AUTOKUMA__KUMA__URL` | The url AutoKuma should use to connect to Uptime Kuma |
| `AUTOKUMA__KUMA__USERNAME` | The username for logging into Uptime Kuma (required unless auth is disabled) |
| `AUTOKUMA__KUMA__PASSWORD` | The password for logging into Uptime Kuma (required unless auth is disabled) |
| `AUTOKUMA__KUMA__MFA_TOKEN` | The MFA token for logging into Uptime Kuma (required if MFA is enabled) |
| `AUTOKUMA__KUMA__HEADERS` | List of HTTP headers used when connecting to Uptime Kuma |
| `AUTOKUMA__KUMA__TAG_NAME` | The name of the AutoKuma tag, used to track managed containers |
| `AUTOKUMA__KUMA__TAG_COLOR` | The color of the AutoKuma tag |
| `AUTOKUMA__KUMA__CONNECT_TIMEOUT` | Timeout for the initial connection to Uptime Kuma |
| `AUTOKUMA__KUMA__CALL_TIMEOUT` | Timeout for calls to Uptime Kuma |
| `AUTOKUMA__KUMA__DEFAULT_SETTINGS` | Provide defaults for all created Monitors, can be overriden by container labels, see the example above for the syntax |
| `AUTOKUMA__DOCKER__SOCKET` | Path to the Docker socket |
| `AUTOKUMA__DOCKER__LABEL_PREFIX` | Prefix used when scanning for container labels |



Expand All @@ -79,6 +90,9 @@ kuma.example.http.name: "Example"
kuma.example.http.url: "https://example.com"
```

Take a look at [all available monitor types](MONITOR_TYPES.md) and the corresponding settings.


AutoKuma also provides support for creating and assigning groups:

```plaintext
Expand All @@ -88,8 +102,23 @@ kuma.mymonitor.http.parent_name: "mygroup"
kuma.mymonitor.http.url: "https://example.com"
```

There are also some text replacements available which will be replaced by details about the corresponding docker container:
| Template | Description | Example Value |
|----------------------|-------------------------------|-------------------------------------------------------------------------|
| `{{container_id}}` | The container id | 92366941fb1f211c573c56d261f3b3e5302f354941f2aa295ae56d5781e97221 |
| `{{image_id}}` | Sha256 of the container image | sha256:c2e38600b252f147de1df1a5ca7964f9c8e8bace97111e56471a4a431639287a |
| `{{image}}` | Name of the container image | ghcr.io/immich-app/immich-server:release |
| `{{container_name}}` | Name of the container | /immich-immich-1 |


### Static Monitors
In addition to reading Monitors from Docker labels, AutoKuma can create Monitors from files, this can be usefull if you have want AutoKuma to manage monitors which aren't directly related to a container.

To create static Monitors just a a .json or .toml file in the directory specified by `AUTOKUMA__STATIC_MONITORS`, take a look at [the examples here](monitors).

In case of static Monitors the id is determined by the filename (without the extension).


Take a look at [all available monitor types](MONITOR_TYPES.md) and the corresponding settings.


## Contributing
Expand Down
5 changes: 5 additions & 0 deletions monitors/json_example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Static Json Example",
"type": "http",
"url": "https://example.com"
}
3 changes: 3 additions & 0 deletions monitors/toml_example.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type = "http"
name = "Static Toml Example"
url = "https://example.com"
14 changes: 13 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,24 @@ pub struct KumaConfig {
pub tag_name: String,
#[config(env = "AUTOKUMA__KUMA__TAG_COLOR", default = "#42C0FB")]
pub tag_color: String,
#[config(env = "AUTOKUMA__KUMA__CONNECT_TIMEOUT", default = 30.0)]
pub connect_timeout: f64,
#[config(env = "AUTOKUMA__KUMA__CALL_TIMEOUT", default = 30.0)]
pub call_timeout: f64,
#[config(env = "AUTOKUMA__KUMA__DEFAULT_SETTINGS", default = "")]
pub default_settings: String,
}

#[derive(confique::Config)]
pub struct DockerConfig {
#[config(env = "AUTOKUMA__DOCKER__ENABLED", default = true)]
pub enabled: bool,
#[config(
env = "AUTOKUMA__DOCKER__SOCKET_PATH",
default = "/var/run/docker.sock"
)]
pub socket_path: String,
#[config(env = "AUTOKUMA__DOCKER__LABEL_PREFOX", default = "kuma")]
#[config(env = "AUTOKUMA__DOCKER__LABEL_PREFIX", default = "kuma")]
pub label_prefix: String,
}

Expand All @@ -35,4 +43,8 @@ pub struct Config {
pub kuma: KumaConfig,
#[config(nested)]
pub docker: DockerConfig,
#[config(env = "AUTOKUMA__SYNC_INTERVAL", default = 5.0)]
pub sync_interval: f64,
#[config(env = "AUTOKUMA__STATIC_MONITORS", default = "/monitors")]
pub static_monitors: String,
}
9 changes: 9 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ pub enum Error {

#[error("Error while trying to parse labels: {0}")]
LabelParseError(String),

#[error("Unable to deserialize: {0}")]
DeserializeError(String),

#[error("Found invalid config '{0}': {1}")]
InvalidConfig(String, String),

#[error("IO error: {0}")]
IO(String),
}

pub type Result<T> = std::result::Result<T, Error>;
36 changes: 13 additions & 23 deletions src/kuma/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,14 @@ impl Worker {
}

async fn get_tags(&self) -> Result<Vec<TagDefinition>> {
self.call("getTags", vec![], "/tags", Duration::from_secs(2))
.await
self.call("getTags", vec![], "/tags").await
}

async fn call<A, T>(
&self,
method: impl Into<String>,
args: A,
result_ptr: impl Into<String>,
timeout: Duration,
) -> Result<T>
where
A: IntoIterator<Item = Value> + Send + Clone,
Expand All @@ -138,7 +136,7 @@ impl Worker {
.emit_with_ack(
method.clone(),
Payload::Text(args.into_iter().collect_vec()),
timeout,
Duration::from_secs_f64(self.config.kuma.call_timeout),
move |message: Payload, _: SocketIO| {
let tx = tx.clone();
let result_ptr = result_ptr.clone();
Expand All @@ -156,10 +154,13 @@ impl Worker {
.await
.map_err(|e| Error::CommunicationError(e.to_string()))?;

tokio::time::timeout(Duration::from_secs(3), rx.recv())
.await
.map_err(|_| Error::CallTimeout(method.clone()))?
.ok_or_else(|| Error::CallTimeout(method))?
tokio::time::timeout(
Duration::from_secs_f64(self.config.kuma.connect_timeout),
rx.recv(),
)
.await
.map_err(|_| Error::CallTimeout(method.clone()))?
.ok_or_else(|| Error::CallTimeout(method))?
}

pub async fn login(
Expand All @@ -177,7 +178,6 @@ impl Worker {
]))
.unwrap()],
"/ok",
Duration::from_secs(2),
)
.await
}
Expand All @@ -187,7 +187,6 @@ impl Worker {
"addTag",
vec![serde_json::to_value(tag.clone()).unwrap()],
"/tag",
Duration::from_secs(2),
)
.await
}
Expand All @@ -207,7 +206,6 @@ impl Worker {
json!(value.unwrap_or_default()),
],
"/ok",
Duration::from_secs(2),
)
.await?;

Expand All @@ -229,7 +227,6 @@ impl Worker {
json!(value.unwrap_or_default()),
],
"/ok",
Duration::from_secs(2),
)
.await?;

Expand All @@ -251,7 +248,6 @@ impl Worker {
json!(value.unwrap_or_default()),
],
"/ok",
Duration::from_secs(2),
)
.await?;

Expand All @@ -260,12 +256,7 @@ impl Worker {

pub async fn delete_monitor(&self, monitor_id: i32) -> Result<()> {
let _: bool = self
.call(
"deleteMonitor",
vec![json!(monitor_id)],
"/ok",
Duration::from_secs(2),
)
.call("deleteMonitor", vec![json!(monitor_id)], "/ok")
.await?;

Ok(())
Expand Down Expand Up @@ -392,7 +383,6 @@ impl Worker {
"add",
vec![serde_json::to_value(&monitor).unwrap()],
"/monitorID",
Duration::from_secs(2),
)
.await?;

Expand Down Expand Up @@ -422,7 +412,6 @@ impl Worker {
"editMonitor",
vec![serde_json::to_value(&monitor).unwrap()],
"/monitorID",
Duration::from_secs(2),
)
.await?;

Expand All @@ -438,7 +427,8 @@ impl Worker {
*self.socket_io.lock().await = None;

let callback_tx = self.event_sender.clone();
let mut builder = ClientBuilder::new(self.config.kuma.url.clone());
let mut builder = ClientBuilder::new(self.config.kuma.url.clone())
.transport_type(rust_socketio::TransportType::Websocket);

for (key, value) in self
.config
Expand Down Expand Up @@ -536,7 +526,7 @@ impl Client {
tokio::spawn(async move {
while let Some((event, payload)) = rx.recv().await {
if let Err(err) = worker_ref.on_event(event, payload).await {
print!("{:?}", err);
println!("{:?}", err);
};
}
});
Expand Down
9 changes: 7 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::sync::Arc;

use util::ResultLogger;

use crate::util::ResultOrDie;

mod config;
mod error;
mod kuma;
Expand Down Expand Up @@ -62,9 +64,12 @@ async fn main() {
.file("config.toml")
.load()
.log_error(|e| format!("Invalid config: {}", e))
.unwrap(),
.unwrap_or_die(1),
);

let sync = sync::Sync::new(config);
let sync = sync::Sync::new(config)
.log_error(|e| format!("Invalid config: {}", e))
.unwrap_or_die(1);

sync.run().await;
}
Loading

0 comments on commit 4553975

Please sign in to comment.