Compare commits
4 Commits
88a751c590
...
v0.1.0
Author | SHA1 | Date | |
---|---|---|---|
5891409fdb | |||
0e9eba4900 | |||
e02737abd1 | |||
4671cf5fac |
@ -6,6 +6,8 @@ Yes, I know Gotify doesn't have "goat" in its name but it sounds like it.
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
Configuration lives in a TOML file which should have (at a minimum) the following:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
server = "https://gotify.example.com"
|
server = "https://gotify.example.com"
|
||||||
app_token = "app_token_from_gotify"
|
app_token = "app_token_from_gotify"
|
||||||
@ -15,7 +17,7 @@ app_token = "app_token_from_gotify"
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
goat_monitor --config ./config.toml --retries -1 -- <COMMAND TO MONITOR>
|
goat_monitor --config ./config.toml --retries 3 -- <COMMAND TO MONITOR>
|
||||||
```
|
```
|
||||||
|
|
||||||
The command can be any shell command including arbitrarily many options / arguments.
|
The command can be any shell command including arbitrarily many options / arguments.
|
||||||
|
@ -17,7 +17,8 @@ from goat_monitor._version import __version__ # type: ignore
|
|||||||
@click.argument("command", nargs=-1, required=False, type=str)
|
@click.argument("command", nargs=-1, required=False, type=str)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--config",
|
"--config",
|
||||||
default="~/.config/goat_monitor.toml",
|
# default="~/.config/goat_monitor.toml",
|
||||||
|
required=True,
|
||||||
type=click.Path(path_type=Path),
|
type=click.Path(path_type=Path),
|
||||||
help="Use a .toml configuration file",
|
help="Use a .toml configuration file",
|
||||||
)
|
)
|
||||||
@ -33,7 +34,13 @@ from goat_monitor._version import __version__ # type: ignore
|
|||||||
default=False,
|
default=False,
|
||||||
help="Print version and exit",
|
help="Print version and exit",
|
||||||
)
|
)
|
||||||
def wrap(command: List[str], config: Path, retries: int, version):
|
@click.option(
|
||||||
|
"--dry-run",
|
||||||
|
is_flag=True,
|
||||||
|
default=False,
|
||||||
|
help="Run command without sending any notifications",
|
||||||
|
)
|
||||||
|
def wrap(command: List[str], config: Path, retries: int, version: bool, dry_run: bool):
|
||||||
"""Wrap an arbitrary command with gotify notifications"""
|
"""Wrap an arbitrary command with gotify notifications"""
|
||||||
|
|
||||||
if version:
|
if version:
|
||||||
@ -45,6 +52,7 @@ def wrap(command: List[str], config: Path, retries: int, version):
|
|||||||
settings = toml.load(f)
|
settings = toml.load(f)
|
||||||
|
|
||||||
# gotify configuration
|
# gotify configuration
|
||||||
|
if not dry_run:
|
||||||
url = settings["server"]
|
url = settings["server"]
|
||||||
app_token = settings["app_token"]
|
app_token = settings["app_token"]
|
||||||
with gotify.Gotify(base_url=url, app_token=app_token) as gotify_connection:
|
with gotify.Gotify(base_url=url, app_token=app_token) as gotify_connection:
|
||||||
@ -58,22 +66,28 @@ def wrap(command: List[str], config: Path, retries: int, version):
|
|||||||
if retries < 0:
|
if retries < 0:
|
||||||
raise ValueError("Invalid number of retries specified")
|
raise ValueError("Invalid number of retries specified")
|
||||||
|
|
||||||
for attempt in range(retries + 1):
|
attempt = 0
|
||||||
|
while attempt <= retries:
|
||||||
# run the command
|
# run the command
|
||||||
result = subprocess.run(
|
with subprocess.Popen(
|
||||||
" ".join(command),
|
" ".join(command),
|
||||||
shell=True,
|
shell=True,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
encoding="utf-8",
|
) as proc:
|
||||||
)
|
stdout = ""
|
||||||
|
while True:
|
||||||
|
c = proc.stdout.read(1)
|
||||||
|
if c == b"":
|
||||||
|
break
|
||||||
|
s = c.decode("utf-8")
|
||||||
|
stdout += s
|
||||||
|
print(s, end="", flush=True)
|
||||||
|
return_code = proc.wait()
|
||||||
|
|
||||||
# TODO: print lines real time as the subprocess runs
|
if return_code:
|
||||||
print(result.stdout, end="")
|
|
||||||
|
|
||||||
if result.returncode:
|
|
||||||
# failed
|
# failed
|
||||||
title = f"Command failed with exit code {result.returncode}"
|
title = f"Command failed with exit code {return_code}"
|
||||||
if attempt < retries:
|
if attempt < retries:
|
||||||
title += f" - Retrying (attempt {attempt+1}/{retries})"
|
title += f" - Retrying (attempt {attempt+1}/{retries})"
|
||||||
else:
|
else:
|
||||||
@ -83,7 +97,7 @@ def wrap(command: List[str], config: Path, retries: int, version):
|
|||||||
title = "Command succeeded"
|
title = "Command succeeded"
|
||||||
|
|
||||||
MAX_LINES = 20
|
MAX_LINES = 20
|
||||||
lines = result.stdout.splitlines()
|
lines = stdout.splitlines()
|
||||||
if len(lines) > MAX_LINES:
|
if len(lines) > MAX_LINES:
|
||||||
lines = lines[-MAX_LINES:]
|
lines = lines[-MAX_LINES:]
|
||||||
message = (
|
message = (
|
||||||
@ -93,14 +107,17 @@ def wrap(command: List[str], config: Path, retries: int, version):
|
|||||||
+ "\n".join(lines)
|
+ "\n".join(lines)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
with gotify.Gotify(base_url=url, app_token=app_token) as gotify_connection:
|
with gotify.Gotify(base_url=url, app_token=app_token) as gotify_connection:
|
||||||
gotify_connection.create_message(message=message, title=title)
|
gotify_connection.create_message(message=message, title=title)
|
||||||
|
|
||||||
if not result.returncode:
|
if not return_code:
|
||||||
# only retry on failure
|
# only retry on failure
|
||||||
break
|
break
|
||||||
|
|
||||||
sys.exit(result.returncode)
|
attempt += 1
|
||||||
|
|
||||||
|
sys.exit(return_code)
|
||||||
|
|
||||||
|
|
||||||
# %% main
|
# %% main
|
||||||
|
Reference in New Issue
Block a user