Add projectfiles

This commit is contained in:
Roxedus
2019-12-06 14:06:20 +01:00
parent 0265f1759c
commit c7824a8be8
7 changed files with 640 additions and 0 deletions

208
.gitignore vendored Normal file
View File

@@ -0,0 +1,208 @@
data/*compose.yml
data/*.xml
# Created by .ignore support plugin (hsz.mobi)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
.idea/
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

93
CLI - Copy.py Normal file
View File

@@ -0,0 +1,93 @@
import argparse
from Converter import Generator, ReadYAML, run
def str2bool(v):
if isinstance(v, bool):
return v
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
parser = argparse.ArgumentParser(description='WIP CLI for compose>template',)
li_ = []
services = ReadYAML().services
service = ""
msg = """Please choose from this list:"""
for i in services:
it = i + 1
msg += "\n" + str(it) + ": " + str(services[i])
li_.append(it)
parser.add_argument('-s', '--service', choices=li_, type=int,
help='list servers, storage, or both (default: %(default)s)')
parser.add_argument('-a', '--automated', action='store_true', help="Generates files from best-guess")
parser.add_argument('-m', '--manual', action='store_true', help="To escape entrypoint imn docker")
parser.add_argument('-t', '--templateurl', help="Sets Template URL")
parser.add_argument('-n', '--name', help="Sets Name")
parser.add_argument('-g', '--repository', help="Sets Repository")
parser.add_argument('-r', '--registry', help="Sets Registry")
parser.add_argument('-u', '--project', help="Sets Project")
parser.add_argument('-i', '--icon', help="Sets Icon URL")
parser.add_argument('-b', '--bindtime', help="Sets Bindtime", type=str2bool)
parser.add_argument('-p', '--privileged', help="Sets Privileged")
parser.add_argument('-o', '--overview', help="Sets Overview")
parser.add_argument('-d', '--description', help="Sets Description")
args = parser.parse_args()
meta_kwargs = {}
if args.description:
meta_kwargs["description"] = args.description
if args.name:
meta_kwargs["name"] = args.name
if args.repository:
meta_kwargs["repository"] = args.repository
if args.registry:
meta_kwargs["registry"] = args.registry
if args.project:
meta_kwargs["project"] = args.project
if args.icon:
meta_kwargs["icon"] = args.icon
if args.bindtime:
meta_kwargs["bindtime"] = args.bindtime
if args.privileged:
meta_kwargs["privileged"] = args.privileged
if args.overview:
meta_kwargs["overview"] = args.overview
if args.automated:
run()
elif args.manual:
print(msg)
elif not args.service:
print(msg)
if args.service:
service = services[args.service - 1]
elm = Generator(service)
elm.metadata(**meta_kwargs)
elm.variable()
elm.network()
elm.data()
elm.write()

93
CLI.py Normal file
View File

@@ -0,0 +1,93 @@
import argparse
from Converter import Generator, ReadYAML, run
def str2bool(v):
if isinstance(v, bool):
return v
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
parser = argparse.ArgumentParser(description='WIP CLI for compose>template',)
li_ = []
services = ReadYAML().services
service = ""
msg = """Please choose from this list:"""
for i in services:
it = i + 1
msg += "\n" + str(it) + ": " + str(services[i])
li_.append(it)
parser.add_argument('-s', '--service', choices=li_, type=int,
help='list servers, storage, or both (default: %(default)s)')
parser.add_argument('-a', '--automated', action='store_true', help="Generates files from best-guess")
parser.add_argument('-m', '--manual', action='store_true', help="To escape entrypoint imn docker")
parser.add_argument('-t', '--templateurl', help="Sets Template URL")
parser.add_argument('-n', '--name', help="Sets Name")
parser.add_argument('-g', '--repository', help="Sets Repository")
parser.add_argument('-r', '--registry', help="Sets Registry")
parser.add_argument('-u', '--project', help="Sets Project")
parser.add_argument('-i', '--icon', help="Sets Icon URL")
parser.add_argument('-b', '--bindtime', help="Sets Bindtime", type=str2bool)
parser.add_argument('-p', '--privileged', help="Sets Privileged")
parser.add_argument('-o', '--overview', help="Sets Overview")
parser.add_argument('-d', '--description', help="Sets Description")
args = parser.parse_args()
meta_kwargs = {}
if args.description:
meta_kwargs["description"] = args.description
if args.name:
meta_kwargs["name"] = args.name
if args.repository:
meta_kwargs["repository"] = args.repository
if args.registry:
meta_kwargs["registry"] = args.registry
if args.project:
meta_kwargs["project"] = args.project
if args.icon:
meta_kwargs["icon"] = args.icon
if args.bindtime:
meta_kwargs["bindtime"] = args.bindtime
if args.privileged:
meta_kwargs["privileged"] = args.privileged
if args.overview:
meta_kwargs["overview"] = args.overview
if args.automated:
run()
elif args.manual:
print(msg)
elif not args.service:
print(msg)
if args.service:
service = services[args.service - 1]
elm = Generator(service)
elm.metadata(**meta_kwargs)
elm.variable()
elm.network()
elm.data()
elm.write()

230
Converter.py Normal file
View File

@@ -0,0 +1,230 @@
import yaml
import xml.etree.ElementTree as ET
from xml.dom import minidom
base = ET.Element('Container', attrib={'version': '2'})
base.append(ET.Comment("Generated with Selfhosters compose>template script"))
class ReadYAML:
def __init__(self):
with open('./data/docker-compose.yml') as f:
self.compose = yaml.load(f, Loader=yaml.FullLoader)
with open('./data/defaults.yml') as f:
self.defaults = yaml.load(f, Loader=yaml.FullLoader)
self.services = self._getservices(self)
def list_field(self, service, field):
decrim = {"environment": "=", "ports": "=", "volumes": ":"}
fields = []
try:
for entries in self.compose['services'][service][field]:
entries_list = []
for entry in entries.split(decrim[field]):
entries_list.append(entry)
fields.append(entries_list)
return fields
except KeyError:
print(f"{field} is not present, skipping")
def list_data(self, service, field):
return self.compose['services'][service][field]
def load_defaults(self, field):
return self.defaults['branding'][field]
@staticmethod
def _getservices(self):
_services = {}
ind = 0
if not _services:
for service in self.compose['services']:
_services[ind] = service
ind += 1
return _services
elif _services:
return _services
else:
print("FATAL ERROR")
class Generator:
def __init__(self, service):
self.elem = base
self.service = service
self.reader = ReadYAML()
self.gen = GenXML(service)
def write(self):
self.gen.write()
def variable(self, **kwargs2: {}):
kwargs = {}
fields = self.reader.list_field(self.service, "environment")
if fields:
for name, value in fields:
if name == "TZ":
continue
best_guess = {"Name": {"PUID": {"Target": "100", "Display": "advanced-hide", "Required": "true"},
"PGID": {"Target": "99", "Display": "advanced-hide", "Required": "true"}},
"should_mask": {"password": {"Mask": "true"}}, "token": {"Mask": "true"}
}
try:
for names in best_guess["Name"][name]:
kwargs[names] = best_guess["Name"][name][names]
except KeyError:
pass
try:
for i in best_guess["should_mask"]:
if i.lower() in name.lower():
kwargs["Mask"] = "true"
except KeyError:
pass
kwargs = {**kwargs, **kwargs2}
GenXML.variable(self, name, value, **kwargs)
return self.elem
def network(self, **kwargs2: {}):
kwargs = {}
ports = self.reader.list_field(self.service, "ports")
if ports:
for host, container in ports:
best_guess = {"Port": {"80": {"Name": "WebUI", "type": "port"}, "8080": {"Name": "WebUI", "type": "port"}}}
try:
container, proto = container.split("/")
kwargs["Protocol"] = proto
except ValueError:
pass
try:
kwargs["Name"] = best_guess["Port"][container]["Name"]
except KeyError:
pass
kwargs = {**kwargs, **kwargs2}
GenXML.networking(self, host, container, **kwargs)
return self.elem
def data(self, **kwargs2: {}):
kwargs = {}
for volumes in self.reader.list_field(self.service, "volumes"):
for host, container, *vargs in volumes:
if vargs:
kwargs["Mode"] = vargs[0]
kwargs = {**kwargs, **kwargs2}
GenXML.data(self, host, container, **kwargs)
return self.elem
def metadata(self, **kwargs2: {}):
kwargs = {}
kwargs["name"] = self.reader.list_data(self.service, "container_name")
kwargs["repository"] = self.reader.list_data(self.service, "image")
kwargs["registry"] = f"https://hub.docker.com/r/{kwargs['repository'].split(':')[0]}"
kwargs["templateurl"] = self.reader.load_defaults("TemplateURLPrefix") + kwargs["name"] + ".xml"
kwargs["icon"] = self.reader.load_defaults("IconPrefix") + kwargs["name"] + ".png"
kwargs = {**kwargs, **kwargs2}
GenXML.metadata(self, **kwargs)
class GenXML:
conf_list = []
def __init__(self, service):
self.elem = base
self.service = service
self.name = "output2"
def write(self):
self._write(self.elem)
def variable(self, name, value, **kwargs):
env = ET.SubElement(self.elem, 'Environment')
variable = ET.SubElement(env, 'Variable')
ET.SubElement(variable, 'Name').text = name
ET.SubElement(variable, 'Value')
ET.SubElement(variable, 'Mode')
atr = {"Name": kwargs.get("Name", name),
"Target": kwargs.get("Target", value),
"Default": kwargs.get("Default", value),
"Mode": kwargs.get("Mode", ""),
"Description": kwargs.get("Description", f"Container Variable: {name}"),
"Type": "Variable",
"Display": kwargs.get("Display", "always"),
"Required": kwargs.get("Required", "false"),
"Mask": kwargs.get("Mask", "false")}
GenXML.conf_list.append(atr)
return self.elem
def networking(self, host, container, **kwargs):
ET.SubElement(self.elem, 'Network').text = "bridge"
net = ET.SubElement(self.elem, 'Networking')
ET.SubElement(net, 'Mode').text = "bridge"
variable = ET.SubElement(net, 'Publish')
ET.SubElement(variable, 'HostPort').text = host
ET.SubElement(variable, 'ContainerPort').text = container
ET.SubElement(variable, 'Protocol').text = kwargs.get("Protocol", "tcp")
atr = {"Name": kwargs.get("Name", "tcp"),
"Target": kwargs.get("Target", container),
"Default": kwargs.get("Default", host),
"Mode": kwargs.get("Protocol", "tcp"),
"Description": kwargs.get("Description", f"Container Port: {container}"),
"Type": "Port",
"Display": kwargs.get("Display", "always"),
"Required": kwargs.get("Required", "false"),
"Mask": kwargs.get("Mask", "false")}
GenXML.conf_list.append(atr)
return self.elem
def data(self, host, container, **kwargs):
vol = ET.SubElement(self.elem, 'Data')
variable = ET.SubElement(vol, 'Volume')
ET.SubElement(variable, 'HostDir')
ET.SubElement(variable, 'ContainerDir').text = container
ET.SubElement(variable, 'Mode').text = kwargs.get("Mode", "rw")
atr = {"Name": kwargs.get("Name", f"Container path {container}"),
"Target": kwargs.get("Target", container),
"Default": kwargs.get("Default", host),
"Mode": kwargs.get("Protocol", "rw"),
"Description": kwargs.get("Description", f"Container Path: {container}"),
"Type": "Path",
"Display": kwargs.get("Display", "always"),
"Required": kwargs.get("Required", "false"),
"Mask": kwargs.get("Mask", "false")}
GenXML.conf_list.append(atr)
return self.elem
def metadata(self, **kwargs):
self.name = kwargs.get("name", "SomeString")
ET.SubElement(self.elem, 'TemplateURL').text = kwargs.get("templateurl", "SomeString")
ET.SubElement(self.elem, 'Name').text = kwargs.get("name", "SomeString")
ET.SubElement(self.elem, 'Repository').text = kwargs.get("repository", "SomeString")
ET.SubElement(self.elem, 'Registry').text = kwargs.get("registry", "SomeString")
ET.SubElement(self.elem, 'Project').text = kwargs.get("project", "SomeString")
ET.SubElement(self.elem, 'Icon').text = kwargs.get("icon", "SomeString")
ET.SubElement(self.elem, 'BindTime').text = kwargs.get("bindtime", "true")
ET.SubElement(self.elem, 'Privileged').text = kwargs.get("privileged", "false")
ET.SubElement(self.elem, 'Overview').text = kwargs.get("overview", "SomeString")
ET.SubElement(self.elem, 'Description').text = kwargs.get("description", "SomeString")
def _write(self, elem):
for atr in self.conf_list:
ET.SubElement(elem, 'Config', attrib=atr)
xmlstr = minidom.parseString(ET.tostring(elem)).toprettyxml(indent=" ")
myfile = open(f"./data/{self.service}.xml", "w")
myfile.write(xmlstr)
print(f"{self.service} Created\n")
def run():
services = ReadYAML().services
for service in services:
elm = Generator(services[service])
elm.metadata()
elm.variable()
elm.network()
elm.data()
GenXML(services[service])._write(elm.elem)
if __name__ == '__main__':
run()

12
Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM python:3.7-alpine3.10
LABEL maintainer="Roxedus"\ state="WIP"
COPY / /app
RUN python3 -m pip install -r /app/requirements.txt
WORKDIR /app/
ENTRYPOINT ["python3", "/app/CLI.py"]
CMD ["-a"]

3
data/defaults.yml Normal file
View File

@@ -0,0 +1,3 @@
branding:
TemplateURLPrefix: https://raw.githubusercontent.com/selfhosters/unRAID-CA-templates/master/templates/
IconPrefix: https://raw.githubusercontent.com/selfhosters/unRAID-CA-templates/master/templates/img/

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
PyYAML