Explorar el Código

Merge branch 'main' into copilot/enhance-customize-settings-logic

xcad hace 1 semana
padre
commit
6fbf587c9e

+ 4 - 0
CHANGELOG.md

@@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Changed
 - Dependency update: typer to v0.21.1 (#1627)
 
+### Fixed
+- Python 3.10+ requirement enforcement - Install script now validates Python version and provides clear upgrade instructions for AlmaLinux/RHEL 9 users
+- Python 3.9 compatibility - Added `from __future__ import annotations` to compose module to support union type syntax on Python 3.9+ (requires Python 3.10+ at runtime)
+
 ## [0.1.3] - 2026-01-06
 
 ### Added

+ 12 - 0
README.md

@@ -23,6 +23,18 @@ Each template includes sensible defaults, best practices, and common configurati
 
 > **Note:** Technologies evolve rapidly. While I actively maintain these templates, always review generated configurations before deploying to production.
 
+### Requirements
+
+- **Python 3.10 or higher** is required
+- Git
+- pipx (automatically installed by the installer script)
+
+> **Note for RHEL/AlmaLinux/Rocky Linux 9 users:** These distributions ship with Python 3.9 by default. You need to install Python 3.11 or later:
+> ```bash
+> sudo dnf install python3.11
+> pipx reinstall --python python3.11 boilerplates
+> ```
+
 ### Installation
 
 #### Automated installer script

+ 2 - 0
cli/modules/compose/__init__.py

@@ -1,5 +1,7 @@
 """Docker Compose module."""
 
+from __future__ import annotations
+
 import logging
 from typing import Annotated
 

+ 2 - 0
cli/modules/compose/validate.py

@@ -1,5 +1,7 @@
 """Docker Compose validation functionality."""
 
+from __future__ import annotations
+
 import logging
 import subprocess
 import tempfile

+ 5 - 0
library/compose/traefik/.env.j2

@@ -17,5 +17,10 @@ AZURE_CLIENT_ID={{ traefik_tls_acme_token }}
 AZURE_CLIENT_SECRET={{ traefik_tls_acme_secret_key }}
 {% elif traefik_tls_certresolver == 'namecheap' %}
 NAMECHEAP_API_KEY={{ traefik_tls_acme_token }}
+{% elif traefik_tls_certresolver == 'ovh' %}
+OVH_ENDPOINT={{ traefik_tls_acme_endpoint | default('ovh-eu') }}
+OVH_APPLICATION_KEY={{ traefik_tls_acme_token }}
+OVH_APPLICATION_SECRET={{ traefik_tls_acme_secret_key }}
+OVH_CONSUMER_KEY={{ traefik_tls_acme_consumer_key }}
 {% endif %}
 {% endif %}

+ 1 - 0
library/compose/traefik/.env.secret.consumer_key.j2

@@ -0,0 +1 @@
+{% if traefik_tls_enabled and swarm_enabled and traefik_tls_certresolver == 'ovh' %}{{ traefik_tls_acme_consumer_key }}{% endif %}

+ 18 - 0
library/compose/traefik/compose.yaml.j2

@@ -142,6 +142,17 @@ services:
       - NAMECHEAP_API_KEY=${NAMECHEAP_API_KEY}
       {% endif %}
       - NAMECHEAP_API_USER={{ traefik_tls_acme_username }}
+      {% elif traefik_tls_certresolver == 'ovh' %}
+      - OVH_ENDPOINT={{ traefik_tls_acme_endpoint | default('ovh-eu') }}
+      {% if swarm_enabled %}
+      - OVH_APPLICATION_KEY_FILE=/run/secrets/{{ service_name }}_token
+      - OVH_APPLICATION_SECRET_FILE=/run/secrets/{{ service_name }}_token_key
+      - OVH_CONSUMER_KEY_FILE=/run/secrets/{{ service_name }}_consumer_key
+      {% else %}
+      - OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
+      - OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
+      - OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}
+      {% endif %}
       {% endif %}
       {% endif %}
     healthcheck:
@@ -159,6 +170,9 @@ services:
       {% if traefik_tls_acme_secret_key %}
       - {{ service_name }}_token_key
       {% endif %}
+      {% if traefik_tls_certresolver == 'ovh' %}
+      - {{ service_name }}_consumer_key
+      {% endif %}
     {% endif %}
     deploy:
       mode: {{ swarm_placement_mode }}
@@ -185,6 +199,10 @@ secrets:
   {{ service_name }}_token_key:
     file: ./.env.secret.token_key
   {% endif %}
+  {% if traefik_tls_certresolver == 'ovh' %}
+  {{ service_name }}_consumer_key:
+    file: ./.env.secret.consumer_key
+  {% endif %}
 {% endif %}
 
 {#

+ 22 - 6
library/compose/traefik/template.yaml

@@ -121,6 +121,7 @@ spec:
         - route53
         - azure
         - namecheap
+        - ovh
         default: cloudflare
         required: true
         needs:
@@ -132,6 +133,15 @@ spec:
         required: true
         needs:
         - traefik_tls_enabled=true
+      traefik_tls_acme_endpoint:
+        description: OVH API endpoint
+        type: str
+        default: ovh-eu
+        required: false
+        needs:
+        - traefik_tls_enabled=true
+        - traefik_tls_certresolver=ovh
+        extra: Common values are ovh-eu, ovh-ca, ovh-us
       traefik_tls_acme_region:
         description: AWS Region
         type: str
@@ -154,9 +164,8 @@ spec:
         required: true
         needs:
         - traefik_tls_enabled=true
-        - traefik_tls_certresolver=azure,godaddy,porkbun,route53
-        extra: AZURE_CLIENT_SECRET, GODADDY_API_SECRET, PORKBUN_SECRET_API_KEY, or
-          AWS_SECRET_ACCESS_KEY
+        - traefik_tls_certresolver=azure,godaddy,ovh,porkbun,route53
+        extra: AZURE_CLIENT_SECRET, GODADDY_API_SECRET, OVH_APPLICATION_SECRET, PORKBUN_SECRET_API_KEY, or AWS_SECRET_ACCESS_KEY
       traefik_tls_acme_subscription_id:
         description: Azure Subscription ID
         type: str
@@ -178,9 +187,8 @@ spec:
         required: true
         needs:
         - traefik_tls_enabled=true
-        - traefik_tls_certresolver=cloudflare,digitalocean,godaddy,namecheap,porkbun
-        extra: CF_DNS_API_TOKEN, DO_AUTH_TOKEN, GODADDY_API_KEY, NAMECHEAP_API_KEY,
-          or PORKBUN_API_KEY
+        - traefik_tls_certresolver=cloudflare,digitalocean,godaddy,namecheap,ovh,porkbun
+        extra: CF_DNS_API_TOKEN, DO_AUTH_TOKEN, GODADDY_API_KEY, NAMECHEAP_API_KEY, OVH_APPLICATION_KEY, or PORKBUN_API_KEY
       traefik_tls_acme_username:
         description: Namecheap API username
         type: str
@@ -188,6 +196,14 @@ spec:
         needs:
         - traefik_tls_enabled=true
         - traefik_tls_certresolver=namecheap
+      traefik_tls_acme_consumer_key:
+        description: OVH Consumer Key
+        type: str
+        sensitive: true
+        required: true
+        needs:
+          - traefik_tls_enabled=true
+          - traefik_tls_certresolver=ovh
       traefik_tls_redirect:
         description: Redirect all HTTP traffic to HTTPS
         type: bool

+ 1 - 1
pyproject.toml

@@ -7,7 +7,7 @@ name = "boilerplates"
 version = "0.1.3"
 description = "CLI tool for managing infrastructure boilerplates"
 readme = "README.md"
-requires-python = ">=3.9"
+requires-python = ">=3.10"
 license = "MIT"
 authors = [ {name = "Christian Lempa"} ]
 keywords = ["boilerplates", "cli", "infrastructure"]

+ 40 - 0
scripts/install.sh

@@ -171,6 +171,43 @@ install_dependencies_linux() {
   fi
 }
 
+check_python_version() {
+  if ! command -v python3 >/dev/null 2>&1; then
+    # Python not installed yet - will be handled by check_dependencies
+    return 0
+  fi
+  
+  local python_version=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null)
+  
+  if [[ -z "$python_version" ]]; then
+    log "Warning: Could not determine Python version"
+    return 0
+  fi
+  
+  local major=$(echo "$python_version" | cut -d. -f1)
+  local minor=$(echo "$python_version" | cut -d. -f2)
+  
+  if [[ "$major" -lt 3 ]] || { [[ "$major" -eq 3 ]] && [[ "$minor" -lt 10 ]]; }; then
+    error "Python 3.10 or higher is required. Found: Python $python_version
+
+Boilerplates requires Python 3.10+ for modern type hint syntax.
+Your system has Python $python_version installed.
+
+On AlmaLinux/RHEL/CentOS/Rocky Linux 9:
+  sudo dnf install python3.11
+  pipx reinstall --python python3.11 boilerplates
+
+On Debian/Ubuntu:
+  sudo apt install python3.11
+  pipx reinstall --python python3.11 boilerplates
+
+Alternatively, use pyenv to install Python 3.11+:
+  https://github.com/pyenv/pyenv#installation"
+  fi
+  
+  log "Python version: $python_version (OK)"
+}
+
 check_dependencies() {
   local missing_deps=()
   
@@ -229,6 +266,9 @@ check_dependencies() {
   fi
   
   log "All dependencies available"
+  
+  # Check Python version after dependencies are installed
+  check_python_version
 }
 
 parse_args() {