Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

bacchus

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bacchus - npm Package Compare versions

Comparing version
1.0.2
to
1.1.0
+8
src/bacchus/kodi.py
from .base import HomeServerApp
class Kodi(HomeServerApp):
"""Kodi"""
def setup(self):
pass
from .base import HomeServerApp
class PiHole(HomeServerApp):
"""Kodi"""
def setup(self):
pass
+2
-1
Metadata-Version: 2.1
Name: bacchus
Version: 1.0.2
Version: 1.1.0
Summary: Home Server solution based on docker

@@ -16,3 +16,4 @@ License: MIT

Requires-Dist: docker (>=4.1,<5.0)
Requires-Dist: jinja2 (>=2.11.2,<3.0.0)
Requires-Dist: netifaces (>=0.10.9,<0.11.0)
Requires-Dist: requests (>=2.22.0,<3.0.0)
[tool.poetry]
name = "bacchus"
version = "1.0.2"
version = "1.1.0"
description = "Home Server solution based on docker"

@@ -20,2 +20,3 @@ authors = ["David Francos <opensource@davidfrancos.net>"]

netifaces = "^0.10.9"
jinja2 = "^2.11.2"

@@ -22,0 +23,0 @@ [tool.poetry.dev-dependencies]

@@ -17,2 +17,3 @@ # -*- coding: utf-8 -*-

'docker>=4.1,<5.0',
'jinja2>=2.11.2,<3.0.0',
'netifaces>=0.10.9,<0.11.0',

@@ -26,3 +27,3 @@ 'requests>=2.22.0,<3.0.0']

'name': 'bacchus',
'version': '1.0.2',
'version': '1.1.0',
'description': 'Home Server solution based on docker',

@@ -29,0 +30,0 @@ 'long_description': None,

@@ -0,3 +1,3 @@

import itertools
import docker
# from bacchus.homeassistant import HomeAssistant
from bacchus.jackett import Jackett

@@ -16,9 +16,20 @@ from bacchus.transmission import Transmission

from bacchus.certificates import CertManager
from bacchus.kodi import Kodi
from bacchus.pihole import PiHole
__all__ = [
CertManager, Nginx, OpenVPN, NextCloud, Transmission, Jackett, Lidarr,
LazyLibrarian, Radarr, Medusa, Jellyfin
DockerCompose, CertManager, Nginx, OpenVPN, NextCloud, Transmission,
Jackett, Lidarr, LazyLibrarian, Radarr, Medusa, Jellyfin, Kodi, PiHole
]
CATEGORIES = {
'base': [CertManager, Nginx, OpenVPN, PiHole],
'media_download':
[Jackett, Lidarr, LazyLibrarian, Radarr, Medusa, Transmission],
'media_management': [Jellyfin],
'media_player': [Kodi],
'cloud': [NextCloud]
}
class HomeServerSetup:

@@ -30,31 +41,39 @@ """Base cmdline class.

"""
def __init__(self, domain, docker_prefix="bacchus", **kwargs):
def __init__(self, domain, **kwargs):
"""Setup providers.
Kwargs will be inherited as metadata, for example, nextcloud will use the nextcloud_username
and nextcloud_password variables
Kwargs will be inherited as metadata
"""
client = docker.from_env()
self.client = docker.from_env()
# tree-like, both compose (wich itself is a provider) and providers
# need access to each other, so we'd do that trough the parent.
self.providers = {}
self.compose = DockerCompose(domain, client, docker_prefix, None, self,
**kwargs)
self.providers.update({
cls.__name__: cls(domain, client, docker_prefix, self.compose,
self, **kwargs)
for cls in __all__
})
self.providers.update({cls.__name__: cls(domain, self, **kwargs)
for cls in __all__})
def configure(self, provider_name=None):
def configure(self, provider_name=None, categories=None):
"""Configure given providers."""
compose = self.providers['DockerCompose']
compose.copy_template()
compose.create_env_files()
compose.start()
if provider_name:
return self.providers[provider_name].setup()
providers = [self.providers[provider_name]]
elif categories:
providers = list(
itertools.chain.from_iterable(
[CATEGORIES[b] for b in categories]))
else:
providers = self.providers.values()
self.compose.copy_template()
self.compose.create_env_files()
self.compose.start()
self.selected_providers = [a.__class__.__name__ for a in providers]
self.selected_categories = categories
for provider in self.providers.values():
for provider in providers:
provider.wait_for_status()
provider.wait_for_config()
provider.setup()
self.compose.restart()
compose.restart()

@@ -17,17 +17,20 @@ from pathlib import Path

"""
def __init__(self, domain, client, docker_prefix, compose, parent, **kwargs):
def __init__(self, domain, parent, **kwargs):
self.service_name = self.__class__.__name__.lower()
self.providers = parent.providers
self.compose = compose
self.parent = parent
self.path = DOCKER_PATH / 'data' / self.service_name
self.domain = domain
self.meta = kwargs
self.meta['project_name'] = docker_prefix
self.meta['project_name'] = 'bacchus'
self.logger = logging.getLogger(self.__class__.__name__)
self.logger.setLevel(logging.DEBUG)
self.path.mkdir(parents=True, exist_ok=True)
self.client = client
self.prefix = docker_prefix
self.client = parent.client
@property
def compose(self):
return self.providers.get('DockerCompose')
@property
def running(self):

@@ -37,3 +40,4 @@ return self.__class__.__name__.lower() in self.compose.services

def container_for(self, service_name):
return next((a for a in self.client.containers.list() if a.id == self.compose.get_service_id(service_name)))
return next((a for a in self.client.containers.list()
if a.id == self.compose.get_service_id(service_name)))

@@ -40,0 +44,0 @@ @property

@@ -8,3 +8,3 @@ from bacchus.base import HomeServerApp

'--dns', 'gandiv5', '-a', '-d', f'private.{self.domain}',
'--email', f'{self.meta["nextcloud_username"]}', 'run'
'--email', f'{self.meta["email"]}', 'run'
]

@@ -18,13 +18,15 @@ if (self.path / 'certificates' /

self.logger.debug(
self.client.containers.run(
'goacme/lego',
command=cmd,
environment={'GANDIV5_API_KEY': self.meta['dns_api_key']},
volumes={
self.path.absolute(): {
'bind': '/.lego',
'mode': 'rw'
}
},
detach=False))
self.client.containers.run('goacme/lego',
command=cmd,
environment={
'GANDIV5_API_KEY':
self.meta['dns_api_key']
},
volumes={
self.path.absolute(): {
'bind': '/.lego',
'mode': 'rw'
}
},
detach=False))
except Exception as err:

@@ -31,0 +33,0 @@ print(err)

@@ -7,23 +7,21 @@ from cleo import Command

class GreetCommand(Command):
"""
Installs bacchus
class InstallCommand(Command):
"""Installs bacchus
install
{domain? : Domain (FQDN) for virtualhosts}
{username? : Nextcloud first user's username}
{password? : Nextcloud first user's password}
{dns? : DNS Provider (ghandi) API key}
{iface? : (Optional) Main interface name}
{provider? : (Optional) Set up only one service}
{--email=? : Your e-mail address}
{--domain=? : Domain (FQDN) on gandi.net}
{--dns=? : DNS Provider (gandi.net) API key}
{--iface=? : (Optional) Main interface name}
{--categories=? : (Optional) Set up specific categories}
{--provider=? : (Optional) Set up only one service}
"""
def handle(self):
"""Handle command"""
setup = HomeServerSetup(domain=self.argument('domain'),
nextcloud_username=self.argument('username'),
nextcloud_password=self.argument('password'),
iface=self.argument('iface'),
dns_api_key=self.argument('dns'))
setup = HomeServerSetup(domain=self.option('domain'),
email=self.option('email'),
iface=self.option('iface'),
dns_api_key=self.option('dns'))
setup.configure(self.argument('provider'))
setup.configure(self.option('provider'), self.option('categories'))

@@ -33,3 +31,3 @@

application = Application()
application.add(GreetCommand())
application.add(InstallCommand())
application.run()

@@ -16,3 +16,5 @@ from pathlib import Path

def env(self):
return {**os.environ, 'COMPOSE_PROJECT_NAME': self.meta['project_name']}
return {
**os.environ, 'COMPOSE_PROJECT_NAME': self.meta['project_name']
}

@@ -33,5 +35,9 @@ def create_env_files(self):

def copy_template(self):
shutil.copyfile((TEMPLATES / 'docker-compose.yml').as_posix(),
(DOCKER_PATH / 'docker-compose.yml').as_posix())
compose = (TEMPLATES / 'docker-compose.yml').read_text()
if not Path('/dev/dri').exists():
compose = compose.replace(""" devices:
- /dev/dri:/dev/dri""", '')
(DOCKER_PATH / 'docker-compose.yml').write_text(compose)
# Hack to allow nginx docker config mount

@@ -46,5 +52,8 @@ nginx_path = DOCKER_PATH / 'data' / 'nginx'

subprocess.check_output(
['docker-compose', '-p', self.meta['project_name'], 'up', '-d' ],
['docker-compose', '-p', self.meta['project_name'], 'up', '-d'],
cwd=DOCKER_PATH,
env={**os.environ, **self.env})
env={
**os.environ,
**self.env
})

@@ -59,10 +68,18 @@ def stop(self):

return subprocess.check_output(['docker-compose', 'ps', '-q', name],
cwd=DOCKER_PATH,
env=self.env).strip().decode()
cwd=DOCKER_PATH,
env=self.env).strip().decode()
def wait_for_status(self):
pass
def setup(self):
pass
@property
def services(self):
services = [a.strip() for a in subprocess.check_output(['docker-compose', 'ps', '--services'],
cwd=DOCKER_PATH,
env=self.env).decode().splitlines()]
services = [
a.strip() for a in subprocess.check_output(
['docker-compose', 'ps', '--services'],
cwd=DOCKER_PATH,
env=self.env).decode().splitlines()
]
return services

@@ -69,0 +86,0 @@

@@ -53,5 +53,3 @@ import json

def setup(self):
self.setup_nginx()

@@ -18,4 +18,2 @@ import json

self.install()
self.logger.debug('Creating new user')
self.create_users()
self.logger.debug('Setting up nginx paths')

@@ -27,18 +25,4 @@ self.setup_paths()

self.setup_onlyoffice()
self.logger.debug('Setting up music')
self.setup_music()
self.logger.debug('Setting up SMS sync')
self.setup_ocsms()
self.logger.debug('Setting up tasks')
self.setup_tasks()
self.logger.debug('Setting up calendar')
self.setup_calendar()
self.logger.debug('Setting up carnet')
self.setup_carnet()
self.logger.debug('Setting up keepass web')
self.setup_keeweb()
self.logger.debug('Setting up deck')
self.setup_deck()
self.logger.debug('Setting up contacts')
self.setup_contacts()
self.logger.debug('Installing apps')
self.setup_apps()
self.logger.debug('Set up nextcloud')

@@ -55,7 +39,2 @@

def create_users(self):
self.occ('user:add', '--password-from-env', '--display-name',
self.meta['nextcloud_username'],
self.meta['nextcloud_username'])
def setup_paths(self):

@@ -67,30 +46,8 @@ self.occ('config:system:set', 'overwritewebroot', '--value', '/')

def setup_music(self):
self.occ('app:install', 'music')
def setup_apps(self):
apps = ('ocsms', 'tasks', 'calendar', 'deck', 'contacts', 'side_menu',
'maps', 'breezedark')
for app in apps:
self.occ('app:install', app)
def setup_ocsms(self):
self.occ('app:install', 'ocsms')
def setup_tasks(self):
self.occ('app:install', 'tasks')
def setup_calendar(self):
"""Setup calendar"""
self.occ('app:install', 'calendar')
def setup_carnet(self):
"""Setup carnet note-taking app"""
self.occ('app:install', 'carnet')
def setup_deck(self):
"""Setup deck kanban"""
self.occ('app:install', 'deck')
def setup_contacts(self):
"""Setup contacts"""
self.occ('app:install', 'contacts')
def setup_keeweb(self):
self.occ('app:install', 'keeweb')
def install_external_links(self):

@@ -190,4 +147,3 @@ """Install top links to all the rest of apps, to centralice everything on nextcloud"""

demux=False,
stderr=False,
environment={'OC_PASS': self.meta['nextcloud_password']}))
stderr=False))
result = self.container.exec_run(args, **kwargs)

@@ -194,0 +150,0 @@ self.logger.debug(result)

from .base import HomeServerApp
from .base import TEMPLATES
from pathlib import Path
from jinja2 import Template
import subprocess

@@ -10,3 +11,24 @@

self.logger.debug('Setting nginx configuration template')
(self.path / 'nginx.conf').write_text(
(TEMPLATES / 'nginx.tpl').read_text().format(domain=self.domain))
template = Template((TEMPLATES / 'nginx.tpl').read_text())
services = {
'Transmission': ["transmission", "9091"],
'Lidarr': ["lidarr", "8686"],
'Jellyfin': ["jellyfin", "8096"],
'NextCloud': ["nextcloud", "80"],
'Medusa': ["medusa", "8081"],
'LazyLibrarian': ["lazylibrarian", "5299"],
'Radarr': ["radarr", "7878"],
'Jackett': ["jackett", "9117"],
'Kodi': ['kodi', '8080'],
'PiHole': ['pihole', '80']
}
context = dict(domain=self.domain,
services=dict([
v for k, v in services.items()
if k in self.parent.selected_providers
]),
selected=self.parent.selected_providers)
(self.path / 'nginx.conf').write_text(template.render(**context))
import json
from contextlib import suppress
from functools import lru_cache

@@ -51,10 +52,10 @@ from .base import TEMPLATES

])
with suppress(Exception):
conn = sqlite3.connect(str((self.path / 'nzbdrone.db').absolute()))
cursor = conn.cursor()
cursor.executemany('insert into Indexers values (?, ?, ?, ?, ?, ?, ?)',
indexers)
conn.commit()
conn.close()
conn = sqlite3.connect(str((self.path / 'nzbdrone.db').absolute()))
cursor = conn.cursor()
cursor.executemany('insert into Indexers values (?, ?, ?, ?, ?, ?, ?)',
indexers)
conn.commit()
conn.close()
def setup(self):

@@ -61,0 +62,0 @@ self.setup_nginx()

@@ -120,3 +120,2 @@ version: '3'

- ./data/media/nextcloud/:/data/
- ./nextcloud_config/:/var/www/html/config/
env_file:

@@ -153,2 +152,3 @@ - .env_nextcloud

- jackett
- kodi
image: nginx

@@ -204,2 +204,16 @@ restart: always

restart: unless-stopped
kodi:
restart: always
image: xayon/docker-kodi-beta:gbm
privileged: True
volumes:
- ./data/kodi_matrix:/root
- /dev/bus/usb:/dev/bus/usb
- /etc/group:/etc/group:ro
- /etc/passwd:/etc/passwd:ro
- /etc/shadow:/etc/shadow:ro
ports:
- 8080:8080
networks:
- common

@@ -206,0 +220,0 @@ networks:

from .base import HomeServerApp
class HomeAssistant(HomeServerApp):
@property
def config_file(self):
return self.path / 'config' / 'configuration.yaml'
def setup(self):
"""Setup home assistant base url."""
self.container.stop()
self.setup_nginx()
self.container.start()
def setup_nginx(self):
"""Setup base url to use it as a proxy server. It requires the FULL url."""
config = self.config_file.read_text()
if not 'base_url' in config:
config += f"http:\n base_url: https://{self.domain}/homeassistant/"
self.config_file.write_text(config)

Sorry, the diff of this file is not supported yet