Add matrix-eavesdrop container image
This builds a container image with a simple eavesdrop bot for Matrix. Change-Id: I5304b4ec974b84886ac969b59cfcec8dec2febf9
This commit is contained in:
parent
4bda99ee47
commit
b58b204a8e
30
docker/matrix-eavesdrop/Dockerfile
Normal file
30
docker/matrix-eavesdrop/Dockerfile
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (C) 2021 Acme Gating, LLC
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
FROM docker.io/opendevorg/python-builder:3.9 as builder
|
||||||
|
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
|
||||||
|
# ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
COPY src /tmp/src
|
||||||
|
RUN assemble
|
||||||
|
|
||||||
|
FROM docker.io/opendevorg/python-base:3.9 as eavesdrop
|
||||||
|
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
|
||||||
|
|
||||||
|
COPY --from=builder /output/ /output
|
||||||
|
RUN /output/install-from-bindep \
|
||||||
|
&& rm -rf /output
|
||||||
|
|
||||||
|
CMD ["eavesdrop"]
|
7
docker/matrix-eavesdrop/src/bindep.txt
Normal file
7
docker/matrix-eavesdrop/src/bindep.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
gcc [compile test]
|
||||||
|
libc6-dev [compile test]
|
||||||
|
libffi-dev [compile test]
|
||||||
|
libolm-dev/buster-backports [compile test]
|
||||||
|
make [compile test]
|
||||||
|
python3-dev [compile test]
|
||||||
|
libolm3/buster-backports
|
0
docker/matrix-eavesdrop/src/eavesdrop/__init__.py
Normal file
0
docker/matrix-eavesdrop/src/eavesdrop/__init__.py
Normal file
155
docker/matrix-eavesdrop/src/eavesdrop/bot.py
Normal file
155
docker/matrix-eavesdrop/src/eavesdrop/bot.py
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
# Copyright (C) 2021 Acme Gating, LLC
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import getpass
|
||||||
|
import socket
|
||||||
|
import yaml
|
||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
from nio import AsyncClient, AsyncClientConfig, LoginResponse, RoomMessageText
|
||||||
|
from nio.store.database import DefaultStore
|
||||||
|
|
||||||
|
|
||||||
|
class Bot:
|
||||||
|
def __init__(self):
|
||||||
|
self.log = logging.getLogger('bot')
|
||||||
|
self.config_path = os.environ.get("MATRIX_CONFIG_FILE",
|
||||||
|
"/config/config.yaml")
|
||||||
|
self.load_config()
|
||||||
|
self.cred_path = os.path.join(
|
||||||
|
self.config['data_dir'], 'credentials.json')
|
||||||
|
self.device_name = socket.gethostname()
|
||||||
|
self.room_map = {}
|
||||||
|
|
||||||
|
async def login(self):
|
||||||
|
config = AsyncClientConfig(
|
||||||
|
store=DefaultStore,
|
||||||
|
store_sync_tokens=True)
|
||||||
|
creds = self.load_creds()
|
||||||
|
if creds:
|
||||||
|
self.log.info("Restoring previous session")
|
||||||
|
self.client = AsyncClient(self.config['homeserver'],
|
||||||
|
store_path=self.config['data_dir'],
|
||||||
|
config=config)
|
||||||
|
self.client.restore_login(
|
||||||
|
user_id=self.config['user_id'],
|
||||||
|
device_id=creds["device_id"],
|
||||||
|
access_token=creds["access_token"],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.log.info("Creating new session")
|
||||||
|
self.client = AsyncClient(self.config['homeserver'],
|
||||||
|
self.config['user_id'],
|
||||||
|
store_path=self.config['data_dir'],
|
||||||
|
config=config)
|
||||||
|
resp = await self.client.login(
|
||||||
|
self.config['password'], device_name=self.device_name)
|
||||||
|
if (isinstance(resp, LoginResponse)):
|
||||||
|
self.save_creds(resp.device_id, resp.access_token)
|
||||||
|
else:
|
||||||
|
self.log.error(resp)
|
||||||
|
raise Exception("Error logging in")
|
||||||
|
# Load the sync tokens
|
||||||
|
self.client.load_store()
|
||||||
|
|
||||||
|
def load_config(self):
|
||||||
|
with open(self.config_path) as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
self.rooms = data['rooms']
|
||||||
|
self.config = data['config']
|
||||||
|
|
||||||
|
def save_creds(self, device_id, token):
|
||||||
|
data = {
|
||||||
|
'device_id': device_id,
|
||||||
|
'access_token': token,
|
||||||
|
}
|
||||||
|
with open(self.cred_path, 'w') as f:
|
||||||
|
json.dump(data, f)
|
||||||
|
|
||||||
|
def load_creds(self):
|
||||||
|
if os.path.exists(self.cred_path):
|
||||||
|
with open(self.cred_path) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def join_rooms(self):
|
||||||
|
new = set()
|
||||||
|
old = set()
|
||||||
|
resp = await self.client.joined_rooms()
|
||||||
|
for room in resp.rooms:
|
||||||
|
old.add(room)
|
||||||
|
for room in self.rooms:
|
||||||
|
self.log.info("Join room %s", room['id'])
|
||||||
|
resp = await self.client.join(room['id'])
|
||||||
|
new.add(resp.room_id)
|
||||||
|
# Store the canonical room id, since the one in the config
|
||||||
|
# file may be an alias
|
||||||
|
self.room_map[resp.room_id] = room
|
||||||
|
os.makedirs(room['path'], exist_ok=True)
|
||||||
|
for room in old-new:
|
||||||
|
self.log.info("Leave room %s", room['id'])
|
||||||
|
await self.client.room_leave(room)
|
||||||
|
|
||||||
|
async def message_callback(self, room, event):
|
||||||
|
config_room = self.room_map.get(room.room_id)
|
||||||
|
if not config_room:
|
||||||
|
return
|
||||||
|
room_name = config_room['id'].split(':')[0]
|
||||||
|
ts = datetime.datetime.utcfromtimestamp(event.server_timestamp/1000.0)
|
||||||
|
event_date = str(ts.date())
|
||||||
|
event_time = str(ts.time())[:8]
|
||||||
|
room_path = config_room['path']
|
||||||
|
if not room_path.startswith('/'):
|
||||||
|
room_path = os.path.join(self.config['log_dir'], room_path)
|
||||||
|
filename = f'{room_name}.{event_date}.log'
|
||||||
|
logpath = os.path.join(room_path, filename)
|
||||||
|
body = event.body
|
||||||
|
line = f'{event_date}T{event_time} <{event.sender}> {body}\n'
|
||||||
|
self.log.info('Logging %s %s', room.room_id, line[:-1])
|
||||||
|
with open(logpath, 'a') as f:
|
||||||
|
f.write(line)
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
await self.login()
|
||||||
|
await self.join_rooms()
|
||||||
|
self.client.add_event_callback(self.message_callback, RoomMessageText)
|
||||||
|
try:
|
||||||
|
await self.client.sync_forever(timeout=30000, full_state=True)
|
||||||
|
finally:
|
||||||
|
await self.client.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def _main():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
bot = Bot()
|
||||||
|
await bot.run()
|
||||||
|
except Exception:
|
||||||
|
bot.log.exception("Error:")
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
asyncio.get_event_loop().run_until_complete(_main())
|
13
docker/matrix-eavesdrop/src/setup.py
Normal file
13
docker/matrix-eavesdrop/src/setup.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='eavesdrop',
|
||||||
|
version='0.0.1',
|
||||||
|
packages=find_packages(),
|
||||||
|
install_requires=['matrix-nio[e2e]', 'PyYaml'],
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'eavesdrop = eavesdrop.bot:main',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
ROOT=$(readlink -fn $(dirname $0)/.. )
|
ROOT=$(readlink -fn $(dirname $0)/.. )
|
||||||
find $ROOT -not -wholename \*.tox/\* -and \( -name \*.sh -or -name \*rc -or -name functions\* \) -print0 | xargs -0 bashate -i E006 -v
|
find $ROOT -type f -not -wholename \*.tox/\* -and \( -name \*.sh -or -name \*rc -or -name functions\* \) -print0 | xargs -0 bashate -i E006 -v
|
||||||
|
31
zuul.d/docker-images/eavesdrop.yaml
Normal file
31
zuul.d/docker-images/eavesdrop.yaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# matrix-eavesdrop jobs
|
||||||
|
- job:
|
||||||
|
name: system-config-build-image-matrix-eavesdrop
|
||||||
|
description: Build a matrix-eavesdrop image.
|
||||||
|
parent: system-config-build-image
|
||||||
|
requires: &matrix-eavesdrop_requires
|
||||||
|
- python-base-3.9-container-image
|
||||||
|
- python-builder-3.9-container-image
|
||||||
|
provides: matrix-eavesdrop-container-image
|
||||||
|
vars: &matrix-eavesdrop_vars
|
||||||
|
docker_images:
|
||||||
|
- context: docker/matrix-eavesdrop
|
||||||
|
repository: opendevorg/matrix-eavesdrop
|
||||||
|
files: &matrix-eavesdrop_files
|
||||||
|
- docker/matrix-eavesdrop/.*
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: system-config-upload-image-matrix-eavesdrop
|
||||||
|
description: Build and upload a matrix-eavesdrop image.
|
||||||
|
parent: system-config-upload-image
|
||||||
|
requires: *matrix-eavesdrop_requires
|
||||||
|
provides: matrix-eavesdrop-container-image
|
||||||
|
vars: *matrix-eavesdrop_vars
|
||||||
|
files: *matrix-eavesdrop_files
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: system-config-promote-image-matrix-eavesdrop
|
||||||
|
description: Promote a previously published matrix-eavesdrop image to latest.
|
||||||
|
parent: system-config-promote-image
|
||||||
|
vars: *matrix-eavesdrop_vars
|
||||||
|
files: *matrix-eavesdrop_files
|
@ -122,6 +122,11 @@
|
|||||||
- name: opendev-buildset-registry
|
- name: opendev-buildset-registry
|
||||||
- name: system-config-build-image-python-builder-3.9
|
- name: system-config-build-image-python-builder-3.9
|
||||||
soft: true
|
soft: true
|
||||||
|
- system-config-build-image-matrix-eavesdrop:
|
||||||
|
dependencies:
|
||||||
|
- name: opendev-buildset-registry
|
||||||
|
- name: system-config-build-image-python-builder-3.9
|
||||||
|
soft: true
|
||||||
- system-config-build-image-python-base-3.7
|
- system-config-build-image-python-base-3.7
|
||||||
- system-config-build-image-python-base-3.8
|
- system-config-build-image-python-base-3.8
|
||||||
- system-config-build-image-python-base-3.9
|
- system-config-build-image-python-base-3.9
|
||||||
@ -247,6 +252,11 @@
|
|||||||
- name: opendev-buildset-registry
|
- name: opendev-buildset-registry
|
||||||
- name: system-config-build-image-python-builder-3.9
|
- name: system-config-build-image-python-builder-3.9
|
||||||
soft: true
|
soft: true
|
||||||
|
- system-config-build-image-matrix-eavesdrop:
|
||||||
|
dependencies:
|
||||||
|
- name: opendev-buildset-registry
|
||||||
|
- name: system-config-build-image-python-builder-3.9
|
||||||
|
soft: true
|
||||||
- system-config-upload-image-python-base-3.7
|
- system-config-upload-image-python-base-3.7
|
||||||
- system-config-upload-image-python-base-3.8
|
- system-config-upload-image-python-base-3.8
|
||||||
- system-config-upload-image-python-base-3.9
|
- system-config-upload-image-python-base-3.9
|
||||||
@ -272,6 +282,7 @@
|
|||||||
- system-config-promote-image-accessbot
|
- system-config-promote-image-accessbot
|
||||||
- system-config-promote-image-refstack
|
- system-config-promote-image-refstack
|
||||||
- system-config-promote-image-ircbot
|
- system-config-promote-image-ircbot
|
||||||
|
- system-config-promote-image-matrix-eavesdrop
|
||||||
- system-config-promote-image-python-base-3.7
|
- system-config-promote-image-python-base-3.7
|
||||||
- system-config-promote-image-python-base-3.8
|
- system-config-promote-image-python-base-3.8
|
||||||
- system-config-promote-image-python-base-3.9
|
- system-config-promote-image-python-base-3.9
|
||||||
|
Loading…
Reference in New Issue
Block a user