first commit

This commit is contained in:
Lee 2024-09-21 05:38:15 +01:00
commit 1f5a1baf95
5 changed files with 264 additions and 0 deletions

30
.gitignore vendored Normal file

@ -0,0 +1,30 @@
# Ignore python bytecode files
__pycache__/
# Ignore pip's log file
pip-log.txt
# Ignore the .egg-info directory created by setuptools
*.egg-info/
# Ignore the .tox directory created by tox
.tox/
# Ignore the cache directory created by pip
pip-cache/
# Ignore the .pytest_cache directory created by pytest
.pytest_cache/
# Ignore the .mypy_cache directory created by mypy
.mypy_cache/
# Ignore the .venv directory created by venv
.venv/
# Ignore the .vscode directory created by vscode
.vscode/
# Ignore the .idea directory created by intellij
.idea/

25
app.py Normal file

@ -0,0 +1,25 @@
import sys
from cliff.app import App
from cliff.commandmanager import CommandManager
from commands import addService
from commands import deleteService
class TraefikHelper(App):
def __init__(self):
super().__init__(
description='Traefik Helper',
version='0.1',
command_manager=CommandManager('commands'),
deferred_help=False,
)
def main(argv=sys.argv[1:]):
app = TraefikHelper()
app.command_manager.add_command('add', addService.AddService)
app.command_manager.add_command('delete', deleteService.DeleteService)
return app.run(argv)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

59
commands/addService.py Normal file

@ -0,0 +1,59 @@
import logging
from urllib.parse import urlparse
from cliff.command import Command
from utils import utils
import os
class AddService(Command):
"Adds a new service to Traefik"
log = logging.getLogger(__name__)
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument('name', help='The name of the service')
parser.add_argument('domain', help='The domain for the service')
parser.add_argument('service', help='The service of the service')
return parser
def take_action(self, parsed_args):
name = parsed_args.name
host = parsed_args.domain
service = parsed_args.service
parsedUrl = urlparse(service)
protocol = parsedUrl.scheme
service = parsedUrl.hostname
port = parsedUrl.port
if not port:
if protocol == "https":
port = 443
elif protocol == "http":
port = 80
# The name of the TLS secret
# Examples:
# - fascinated.cc -> fascinated-cc
# - bob.fascinated.cc -> fascinated-cc
# - bob.local.fascinated.cc -> local-fascinated-cc
host_parts = host.split('.')
if len(host_parts) > 2:
tls_secret = '-'.join(host_parts[1:]) # Join everything from the second part onward
else:
tls_secret = '-'.join(host_parts) # Use the entire host for two-part domains
# Define the path to save the YAML file
filePath = f'{utils.getServicesPath()}/{host}.yml'
# Check if the service file already exists, if so exit
if os.path.exists(filePath):
print(f"Service \"{name}\" already exists ({filePath})")
return
isInstalled = utils.checkIfKubectlInstalled()
if not isInstalled:
self.log.error("kubectl is not installed")
return 1
utils.createService(filePath, name, host, service, protocol, port, tls_secret)

33
commands/deleteService.py Normal file

@ -0,0 +1,33 @@
import logging
from cliff.command import Command
from utils import utils
import os
class DeleteService(Command):
"Deletes a service from Traefik"
log = logging.getLogger(__name__)
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument('domain', help='The domain for the service')
return parser
def take_action(self, parsed_args):
host = parsed_args.domain
# Define the path to the YAML file
filePath = f'{utils.getServicesPath()}/{host}.yml'
# Check if the service file exists, if not exit
if not os.path.exists(filePath):
print(f"Service \"{host}\" does not exist")
return
isInstalled = utils.checkIfKubectlInstalled()
if not isInstalled:
self.log.error("kubectl is not installed")
return 1
utils.deleteService(filePath, host)

117
utils/utils.py Normal file

@ -0,0 +1,117 @@
import subprocess
import logging
import os
log = logging.getLogger(__name__)
baseServices = """kind: Service
apiVersion: v1
metadata:
name: {name}-external
namespace: traefik
spec:
type: ExternalName
externalName: {service}
ports:
- name: {protocol}
port: {port}
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: {name}-external-ingress
namespace: traefik
annotations:
kubernetes.io/ingress.class: traefik-external
spec:
entryPoints:
- websecure
routes:
- match: Host(`{host}`)
kind: Rule
services:
- name: {name}-external
port: {port}
tls:
secretName: {tls_secret}
"""
def getServicesPath():
"""
Get the path to the services directory
"""
# Get from the environment variable
if os.getenv("SERVICES_PATH"):
return os.getenv("SERVICES_PATH")
# Fallback to my pc cause im lazy
return "C:/Users/Liam/Nextcloud/Kubernetes/traefik/external"
def checkIfKubectlInstalled():
"""
Check if kubectl is installed
"""
try:
subprocess.check_output(['kubectl', 'version'])
return True
except subprocess.CalledProcessError:
return False
def runKubectl(command):
"""
Run kubectl with the given command
"""
args = command.split(' ')
result = subprocess.run(['kubectl'] + args, capture_output=True, text=True)
if result.returncode != 0:
print(f"Error running kubectl: \n{result.stderr}")
else:
print(f"kubectl output: \n{result.stdout}")
def createService(filePath, name, host, service, protocol, port, tls_secret):
"""
Create a new service and apply it using kubectl
"""
# Generate the YAML content for the service and ingress route
serviceContent = baseServices.format(
name=name,
host=host,
service=service,
protocol=protocol,
port=port,
tls_secret=tls_secret
)
# Write the YAML content to the file and check for errors
try:
with open(filePath, 'w') as f:
f.write(serviceContent)
print(f"Service definition written to {filePath}")
except Exception as e:
print(f"Error writing service file: {e}")
return
# Apply the service using kubectl
runKubectl(f'apply -f {filePath}')
log.info(f"Service {name} created")
log.info(f"Domain: http://{host}")
def deleteService(filePath, name):
"""
Delete a service and apply it using kubectl
"""
# Delete the service using kubectl
runKubectl(f'delete -f {filePath}')
# Remove the service file
try:
os.remove(filePath)
print(f"Service definition deleted from {filePath}")
except Exception as e:
print(f"Error deleting service file: {e}")
return
log.info(f"Service {name} deleted")