This commit is contained in:
2025-11-30 14:14:01 +01:00
parent ce5765ed78
commit 8354f41f09
4 changed files with 150 additions and 10 deletions

View File

@@ -0,0 +1,39 @@
services:
bitwarden:
environment:
WEBSOCKET_ENABLED: 'true'
SIGNUPS_ALLOWED: 'true'
DOMAIN: https://pw.sectorq.eu
SMTP_HOST: mail.sectorq.eu
SMTP_FROM: jaydee@sectorq.eu
SMTP_PORT: '465'
SMTP_SSL: 'true'
SMTP_USERNAME: jaydee@sectorq.eu
SMTP_PASSWORD: $SMTP_PASSWORD
ADMIN_TOKEN: $ADMIN_PASSWORD
image: ${DOCKER_REGISTRY:-}vaultwarden/server:latest
ports:
- target: 80
published: 8181
protocol: tcp
mode: ingress
restart: ${RESTART:-unless-stopped}
volumes:
- /share/docker_data/bitwarden/bw-data:/data
deploy:
labels:
com.centurylinklabs.watchtower.enable: 'true'
homepage.container: vaultwarden
homepage.description: Password manager
homepage.group: Utilities
homepage.href: https://pw.sectorq.eu
homepage.icon: bitwarden.png
homepage.name: Bitwarden
homepage.server: my-docker
homepage.weight: '1'
wud.watch: 'true'
wud.watch.digest: 'true'
replicas: 1
placement:
constraints:
- node.role == manager

View File

@@ -23,17 +23,17 @@ services:
restart_policy:
condition: any
labels:
com.centurylinklabs.watchtower.enable: true
com.centurylinklabs.watchtower.enable: 'true'
homepage.container: vaultwarden
homepage.description: Password manager
homepage.group: Utilities
homepage.description: password manager
homepage.group: utilities
homepage.href: https://pw.sectorq.eu
homepage.icon: bitwarden.png
homepage.name: Bitwarden
homepage.name: bitwarden
homepage.server: my-docker
homepage.weight: 1
wud.watch: true
wud.watch.digest: true
homepage.weight: '1'
wud.watch: 'true'
wud.watch.digest: 'true'
placement:
constraints:
- node.role == manager

View File

@@ -46,9 +46,11 @@ def convert_service(service):
continue
swarm_service[key] = value
for en in swarm_service['environment']:
#print(f"Environment Variable: {en} : {swarm_service['environment'][en]}")
swarm_service['environment'][en] = str(swarm_service['environment'][en]).lower()
# for en in swarm_service['environment']:
# #print(f"Environment Variable: {en} : {swarm_service['environment'][en]}")
# print(en)
# print(swarm_service['environment'][en])
# swarm_service['environment'][en] = str(swarm_service['environment'][en]).lower()
#print("Deploy Section:")
#print(swarm_service)
# Merge user deploy section if present

99
yaml_convert2.py Normal file
View File

@@ -0,0 +1,99 @@
import yaml
import sys
stack_name = sys.argv[1]
INPUT_FILE = f"{stack_name}/docker-compose.yml"
OUTPUT_FILE = f"__swarm/{stack_name}/{stack_name}-stack.yml"
def convert_ports(ports):
"""Convert short port syntax to Swarm long syntax."""
result = []
for p in ports:
if isinstance(p, str):
# format: "8080:80"
pub, tgt = p.split(":")
result.append({
"target": int(tgt),
"published": int(pub),
"protocol": "tcp",
"mode": "ingress"
})
else:
result.append(p)
return result
def to_str_lower(value):
"""Convert value to string. Booleans become lowercase 'true'/'false'."""
if isinstance(value, bool):
return "true" if value else "false"
return str(value)
def env_list_to_dict(env_list):
"""Convert environment from list ['KEY=VAL'] to dict {KEY: VAL} as strings."""
env_dict = {}
for item in env_list:
key, value = item.split("=", 1)
# convert 'true'/'false' strings to lowercase
if value.lower() in ["true", "false"]:
env_dict[key] = value.lower()
else:
env_dict[key] = str(value)
return env_dict
def ensure_labels_as_string(labels):
"""Ensure all label values are strings, lowercase for booleans."""
return {k: to_str_lower(v) for k, v in labels.items()}
def convert_compose_to_swarm(data):
services = data.get("services", {})
for name, svc in services.items():
# 1) Convert environment list → dict (strings)
if "environment" in svc and isinstance(svc["environment"], list):
svc["environment"] = env_list_to_dict(svc["environment"])
# 2) Ensure deploy exists
deploy = svc.setdefault("deploy", {})
# 3) Move labels into deploy.labels, all as strings (lowercase booleans)
if "labels" in svc:
deploy.setdefault("labels", {})
if isinstance(svc["labels"], dict):
deploy["labels"].update(ensure_labels_as_string(svc["labels"]))
elif isinstance(svc["labels"], list):
for label in svc["labels"]:
key, value = label.split("=", 1)
deploy["labels"][key] = value.lower() if value.lower() in ["true", "false"] else str(value)
del svc["labels"]
# 4) Default replicas
deploy.setdefault("replicas", 1)
# 5) Add placement constraint
deploy.setdefault("placement", {})
deploy["placement"].setdefault("constraints", [])
if "node.role == manager" not in deploy["placement"]["constraints"]:
deploy["placement"]["constraints"].append("node.role == manager")
# 6) Convert ports to long format
if "ports" in svc:
svc["ports"] = convert_ports(svc["ports"])
# 7) Remove container_name (not allowed in Swarm)
svc.pop("container_name", None)
return data
def main():
with open(INPUT_FILE, "r") as f:
compose = yaml.safe_load(f)
swarm = convert_compose_to_swarm(compose)
with open(OUTPUT_FILE, "w") as f:
yaml.dump(swarm, f, sort_keys=False)
print(f"Swarm stack file written to {OUTPUT_FILE}")
if __name__ == "__main__":
main()