Skip to content

Commit

Permalink
Merge branch 'add-gotify' into 'master'
Browse files Browse the repository at this point in the history
Add gotify

See merge request ix.ai/cioban!43
  • Loading branch information
tlex committed Feb 5, 2020
2 parents 4c8853f + 67734dc commit c67525b
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 37 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![Gitlab Project](https://img.shields.io/badge/GitLab-Project-554488.svg)](https://gitlab.com/ix.ai/cioban/)


A docker swarm service for automatically updating your services to the latest image tag push. You can enable telegram notifications, so you get a message after every successful update.
A docker swarm service for automatically updating your services to the latest image tag push. You can enable telegram or gotify notifications, so you get a message after every successful update.

## Usage Examples

Expand Down Expand Up @@ -52,6 +52,8 @@ Cioban will try to update your services every 5 minutes by default. The followin
| `FILTER_SERVICES` | - | Anything accepted by the filtering flag in `docker service ls`. Example: `label=ai.ix.auto-update=true` |
| `TELEGRAM_TOKEN` | - | See the [Telegram documentation](https://core.telegram.org/bots#creating-a-new-bot) how to get a new token |
| `TELEGRAM_CHAT_ID` | - | See this question on [stackoverflow](https://stackoverflow.com/questions/32423837/telegram-bot-how-to-get-a-group-chat-id) |
| `GOTIFY_URL` | - | The URL of the [Gotify](https://gotify.net/) server |
| `GOTIFY_TOKEN` | - | The APP token for Gotify |
| `NOTIFY_INCLUDE_NEW_IMAGE` | - | Set this variable to anything to include the new image (including digest) in the update notification |
| `NOTIFY_INCLUDE_OLD_IMAGE` | - | Set this variable to anything to include the old image (including digest) in the update notification |
| `LOGLEVEL` | `INFO` | [Logging Level](https://docs.python.org/3/library/logging.html#levels) |
Expand Down
47 changes: 23 additions & 24 deletions cioban/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,58 +23,57 @@
filters = os.environ.get('FILTER_SERVICES')
filters = filters.split('=', 1)
options['filters'] = {filters[0]: filters[1]}
log.info('FILTER_SERVICES: "{}"'.format(options['filters']))
else:
log.info('FILTER_SERVICES not set')
log.info(f"FILTER_SERVICES: '{options['filters']}'")

if os.environ.get('BLACKLIST_SERVICES'):
blacklist = os.environ.get('BLACKLIST_SERVICES')
options['blacklist'] = blacklist.split(' ')
log.info('BLACKLIST_SERVICES: "{}"'.format(options['blacklist']))
else:
log.info('BLACKLIST_SERVICES not set')
log.info(f"BLACKLIST_SERVICES: '{options['blacklist']}'")

if os.environ.get('TELEGRAM_TOKEN'):
options['telegram_token'] = os.environ.get('TELEGRAM_TOKEN')
log.info('TELEGRAM_TOKEN is set')
else:
log.info('TELEGRAM_TOKEN not set')

if os.environ.get('TELEGRAM_CHAT_ID'):
options['telegram_chat_id'] = os.environ.get('TELEGRAM_CHAT_ID')
log.info('TELEGRAM_CHAT_ID is set')
else:
log.info('TELEGRAM_CHAT_ID not set')

if os.environ.get('GOTIFY_URL'):
options['gotify_url'] = os.environ.get('GOTIFY_URL')
log.info(f"GOTIFY_URL: {options['gotify_url']}")

if os.environ.get('GOTIFY_TOKEN'):
options['gotify_token'] = os.environ.get('GOTIFY_TOKEN')
log.info(f"GOTIFY_TOKEN is set")

if os.environ.get('NOTIFY_INCLUDE_NEW_IMAGE'):
options['notify_include_new_image'] = True
log.info('NOTIFY_INCLUDE_NEW_IMAGE is set')
else:
log.info('NOTIFY_INCLUDE_NEW_IMAGE not set')

if os.environ.get('NOTIFY_INCLUDE_OLD_IMAGE'):
options['notify_include_old_image'] = True
log.info('NOTIFY_INCLUDE_OLD_IMAGE is set')
else:
log.info('NOTIFY_INCLUDE_OLD_IMAGE not set')

if options.get('telegram_token') and options.get('telegram_chat_id'):
options['notifiers'].append('telegram')

if options.get('gotify_url') and options.get('gotify_token'):
options['notifiers'].append('gotify')

options['sleep_time'] = os.environ.get('SLEEP_TIME', '5m')
log.info('SLEEP_TIME: {}'.format(options['sleep_time']))
log.info(f"SLEEP_TIME: {options['sleep_time']}")

options['prometheus_port'] = int(os.environ.get('PORT', 9308))
log.info('PORT: {}'.format(options['prometheus_port']))

log.warning(
"Starting {} {}-{} with prometheus metrics on port {}".format(
__package__,
constants.VERSION,
constants.BUILD,
options['prometheus_port'],
)
log.info(f"PORT: {options['prometheus_port']}")

startup_message = "Starting {} {}-{} with prometheus metrics on port {}".format(
__package__,
constants.VERSION,
constants.BUILD,
options['prometheus_port'],
)
log.warning(startup_message)

c = cioban.Cioban(**options)
c.notify(title="CIOBAN Startup", message=startup_message)
c.run()
12 changes: 7 additions & 5 deletions cioban/cioban.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
""" A docker swarm service for automatically updating your services to the latest image tag push. """

import logging
import requests
import pause
import docker
from prometheus_client import start_http_server
Expand All @@ -21,8 +22,6 @@ class Cioban():
'sleep_time': '5m',
'prometheus_port': 9308,
'notifiers': [],
'telegram_chat_id': None,
'telegram_token': None,
'notify_include_new_image': False,
'notify_include_old_image': False,
}
Expand All @@ -34,7 +33,7 @@ def __init__(self, **kwargs):
if k in self.settings:
self.settings[k] = v
else:
log.debug(f'{k} not found in settings')
log.debug(f'{k} not found in settings. Ignoring.')

prometheus.PROM_INFO.info({'version': f'{constants.VERSION}'})

Expand Down Expand Up @@ -66,7 +65,6 @@ def __init__(self, **kwargs):
if notifier.lower() in k.lower():
notifier_options.update({k.lower(): v})
self.notifiers.register(notifier, **notifier_options)
log.debug('Registered {}'.format(notifier))

log.debug('Cioban initialized')

Expand All @@ -88,7 +86,7 @@ def __get_updated_image(self, image, image_sha):
updated_image = None
try:
registry_data = self.docker.images.get_registry_data(image)
except docker.errors.APIError as error:
except (docker.errors.APIError, requests.exceptions.ReadTimeout) as error:
log.error(f'Failed to retrieve the registry data for {image}. The error: {error}')

if registry_data:
Expand Down Expand Up @@ -191,3 +189,7 @@ def get_services(self):
log.debug(f'Blacklisted {blacklist_service}')
services.remove(service)
return services

def notify(self, **kwargs):
""" Sends a notification through the registered notifiers """
self.notifiers.notify(**kwargs)
10 changes: 6 additions & 4 deletions cioban/notifiers/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CoreNotifiers():

notifiers = [
'telegram',
'gotify',
]

registered = []
Expand All @@ -37,11 +38,12 @@ def register(self, notifier, **kwargs):
for n in self.notifiers:
if n == notifier:
instance = importlib.import_module(f'cioban.notifiers.{notifier}_notifier')
self.registered.append(instance.Notifier(**kwargs))
self.registered.append({notifier: instance.Notifier(**kwargs)})
log.debug(f'Registered {notifier}')

def notify(self, **kwargs):
""" dispatches a notification to the registered notifiers """
log.debug('Sending notification')
for notifier in self.registered:
notifier.notify(**kwargs)
for i in self.registered:
for notifier in i:
log.debug(f'Sending notification to {notifier}')
i[notifier].notify(**kwargs)
51 changes: 51 additions & 0 deletions cioban/notifiers/gotify_notifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" Gotify """

import logging
from urllib.parse import urljoin
import requests
from . import core

log = logging.getLogger('cioban')


class Notifier():
""" The notify class """

def __init__(self, **kwargs):
self.token = kwargs['gotify_token']
self.url = urljoin(kwargs['gotify_url'], f'/message?token={self.token}')
log.debug(f"Initialized with {kwargs['gotify_url']}")

def __post_message(self, title, message):
""" sends the notification to telegram """
try:
resp = requests.post(self.url, json={
'title': title,
'message': message,
})
except requests.exceptions.RequestException as e:
# Print exception if reqeuest fails
log.error(f'Could not connect to Gotify server. The error: {e}')

# Print request result if server returns http error code
if resp.status_code is not requests.codes.ok: # pylint: disable=no-member
log.error(f'{bytes.decode(resp.content)}')
else:
log.info("Sent message to gotify")
log.debug(f"Message: {message}")

def notify(self, title="CIOBAN: Service Updated", **kwargs):
""" parses the arguments, formats the message and dispatches it """
log.debug('Sending message to gotify')
message = ""
if kwargs.get('message'):
message = kwargs['message']
else:
for k, v in kwargs.items():
message += f'{core.key_to_title(k)}: {v}\n'
self.__post_message(title, message)

def noop(self):
""" Does nothing """
9 changes: 6 additions & 3 deletions cioban/notifiers/telegram_notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ def __post_message(self, message):
def notify(self, title="CIOBAN: Service Updated", **kwargs):
""" parses the arguments, formats the message and dispatches it """
log.debug('Sending notification to telegram')
message = '{0} <b>{1}</b> {0}\n'.format(u'\U00002611', title)
for k, v in kwargs.items():
message += '<b>{}</b>: {}\n'.format(core.key_to_title(k), v)
message = f'<b>{title}</b>\n'
if kwargs.get('message'):
message += kwargs['message']
else:
for k, v in kwargs.items():
message += f'{core.key_to_title(k)}: {v}\n'
self.__post_message(message)

def noop(self):
Expand Down

0 comments on commit c67525b

Please sign in to comment.