first commit
This commit is contained in:
commit
1f5a1baf95
30
.gitignore
vendored
Normal file
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
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
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
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
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")
|
Loading…
Reference in New Issue
Block a user