ssulav commented on code in PR #9247:
URL: https://github.com/apache/ozone/pull/9247#discussion_r2651528195


##########
tools/installer/ozone_installer.py:
##########
@@ -0,0 +1,499 @@
+#!/usr/bin/env python3
+
+import argparse
+import json
+import os
+import re
+import shlex
+import subprocess
+import sys
+import tempfile
+from pathlib import Path
+from typing import List, Optional, Tuple
+
+ANSIBLE_ROOT = Path(__file__).resolve().parent
+ANSIBLE_CFG = ANSIBLE_ROOT / "ansible.cfg"
+PLAYBOOKS_DIR = ANSIBLE_ROOT / "playbooks"
+LOGS_DIR = ANSIBLE_ROOT / "logs"
+LAST_FAILED_FILE = LOGS_DIR / "last_failed_task.txt"
+LAST_RUN_FILE = LOGS_DIR / "last_run.json"
+
+DEFAULTS = {
+    "install_base": "/opt/ozone",
+    "data_base": "/data/ozone",
+    "ozone_version": "2.0.0",
+    "jdk_major": 17,
+    "service_user": "ozone",
+    "service_group": "ozone",
+    "dl_url": "https://dlcdn.apache.org/ozone";,
+    "JAVA_MARKER": "Apache Ozone Installer Java Home",
+    "ENV_MARKER": "Apache Ozone Installer Env",
+    "start_after_install": True,
+    "use_sudo": True,
+}
+
+def parse_args(argv):
+    p = argparse.ArgumentParser(
+        description="Ozone Ansible Installer (Python trigger) - mirrors bash 
installer flags"
+    )
+    p.add_argument("-H", "--host", help="Target host(s). Non-HA: host. HA: 
comma-separated or brace expansion host{1..n}")
+    p.add_argument("-m", "--auth-method", choices=["password", "key"], 
default=None)
+    p.add_argument("-p", "--password", help="SSH password (for 
--auth-method=password)")
+    p.add_argument("-k", "--keyfile", help="SSH private key file (for 
--auth-method=key)")
+    p.add_argument("-v", "--version", help="Ozone version (e.g., 2.0.0) or 
'local'")
+    p.add_argument("-i", "--install-dir", help=f"Install root (default: 
{DEFAULTS['install_base']})")
+    p.add_argument("-d", "--data-dir", help=f"Data root (default: 
{DEFAULTS['data_base']})")
+    p.add_argument("-s", "--start", action="store_true", help="Initialize and 
start after install")
+    p.add_argument("-M", "--cluster-mode", choices=["non-ha", "ha"], 
help="Force cluster mode (default: auto by host count)")
+    p.add_argument("-r", "--role-file", help="Role file (YAML) for HA mapping 
(optional)")
+    p.add_argument("-j", "--jdk-version", type=int, choices=[17, 21], 
help="JDK major version (default: 17)")
+    p.add_argument("-c", "--config-dir", help="Config dir (optional, templates 
are used by default)")
+    p.add_argument("-x", "--clean", action="store_true", help="(Reserved) 
Cleanup before install [not yet implemented]")
+    p.add_argument("-l", "--ssh-user", help="SSH username (default: root)")
+    p.add_argument("-S", "--use-sudo", action="store_true", help="Run remote 
commands via sudo (default)")
+    p.add_argument("-u", "--service-user", help="Service user (default: 
ozone)")
+    p.add_argument("-g", "--service-group", help="Service group (default: 
ozone)")
+    # Local extras
+    p.add_argument("--local-path", help="Path to local Ozone build (contains 
bin/ozone)")
+    p.add_argument("--dl-url", help="Upstream download base URL")
+    p.add_argument("--yes", action="store_true", help="Non-interactive; accept 
defaults for missing values")
+    p.add_argument("-R", "--resume", action="store_true", help="Resume play at 
last failed task (if available)")
+    return p.parse_args(argv)
+
+def _validate_local_ozone_dir(path: Path) -> bool:
+    """
+    Returns True if 'path/bin/ozone' exists and is executable.
+    """
+    ozone_bin = path / "bin" / "ozone"
+    try:
+        return ozone_bin.exists() and os.access(str(ozone_bin), os.X_OK)
+    except OSError:
+        return False
+
+def prompt(prompt_text, default=None, secret=False, yes_mode=False):
+    if yes_mode:
+        return default
+    try:
+        if default:
+            text = f"{prompt_text} [{default}]: "
+        else:
+            text = f"{prompt_text}: "
+        if secret:
+            import getpass
+            val = getpass.getpass(text)
+        else:
+            val = input(text)
+        if not val and default is not None:
+            return default
+        return val
+    except EOFError:
+        return default
+
+def _semver_key(v: str) -> Tuple[int, int, int, str]:
+    """
+    Convert version like '2.0.0' or '2.1.0-RC0' to a sortable key.
+    Pre-release suffix sorts before final.
+    """
+    try:
+        core, *rest = v.split("-", 1)
+        major, minor, patch = core.split(".")
+        suffix = rest[0] if rest else ""
+        return (int(major), int(minor), int(patch), suffix)
+    except Exception:
+        return (0, 0, 0, v)
+
+def fetch_available_versions(dl_url: str, limit: int = 30) -> List[str]:
+    """
+    Fetch available Ozone versions from the download base. Returns 
newest-first.
+    """
+    try:
+        import urllib.request
+        with urllib.request.urlopen(dl_url, timeout=10) as resp:
+            html = resp.read().decode("utf-8", errors="ignore")
+        # Apache directory listing usually has anchors like href="2.0.0/"
+        candidates = set(m.group(1) for m in 
re.finditer(r'href="([0-9]+\.[0-9]+\.[0-9]+(?:-[A-Za-z0-9]+)?)\/"', html))
+        versions = sorted(candidates, key=_semver_key, reverse=True)
+        if limit and len(versions) > limit:
+            versions = versions[:limit]
+        return versions
+    except Exception:
+        return []
+
+def choose_version_interactive(versions: List[str], default_version: str, 
yes_mode: bool) -> Optional[str]:
+    """
+    Present a numbered list and prompt user to choose a version.
+    Returns selected version string or None if not chosen.
+    """
+    if not versions:
+        return None
+    if yes_mode:
+        return versions[0]
+    print("Available Ozone versions:")
+    for idx, ver in enumerate(versions, start=1):
+        print(f"  {idx}) {ver}")
+    while True:

Review Comment:
   Done.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to