This is an automated email from the ASF dual-hosted git repository.
ssulav pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone-installer.git
The following commit(s) were added to refs/heads/master by this push:
new d8aa6ee HDDS-14521: Read hosts from file, add verbose flag and option
to override python interpreter
d8aa6ee is described below
commit d8aa6ee5857f08a97f4e496dff7313550c927e45
Author: Soumitra Sulav <[email protected]>
AuthorDate: Thu Jan 29 06:14:36 2026 +0530
HDDS-14521: Read hosts from file, add verbose flag and option to override
python interpreter
---
.gitignore | 3 +-
README.md | 119 +++++++++++++++++++++++++++++++++++--
ansible.cfg | 3 +-
ansible.cfg => hosts.txt.example | 44 +++++++-------
inventories/dev/group_vars/all.yml | 2 -
ozone_installer.py | 97 ++++++++++++++++++++++++------
playbooks/cluster.yml | 61 +++++++++++++++----
roles/cleanup/tasks/main.yml | 4 +-
roles/java/tasks/main.yml | 1 +
roles/ozone_fetch/tasks/main.yml | 2 +
roles/ozone_ui/tasks/main.yml | 26 ++++----
11 files changed, 284 insertions(+), 78 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7859f36..37ccc66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
logs/**
-*.pyc
\ No newline at end of file
+*.pyc
+hosts.txt
\ No newline at end of file
diff --git a/README.md b/README.md
index ea393b8..6a3e710 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,8 @@ Ports and service behavior follow Ozone defaults; consult the
official documenta
## Software Requirements
-- Controller: Python 3.10–3.12 (prefer 3.11) and pip
+### Controller node requirements
+- Python 3.10–3.12 (prefer 3.11) and pip
- Ansible Community 10.x (ansible-core 2.17.x)
- Python packages (installed via `requirements.txt`):
- `ansible-core==2.17.*`
@@ -43,10 +44,55 @@ Ports and service behavior follow Ozone defaults; consult
the official documenta
- RHEL/CentOS/Rocky: `sudo yum install -y sshpass` or `sudo dnf install -y
sshpass`
- SUSE: `sudo zypper in -y sshpass`
-### Controller node requirements
-- Can be local or remote.
-- Must be on the same network as the target hosts.
-- Requires SSH access (key or password).
+### Managed node requirements (target hosts)
+- **Python 3.7 or higher** (required by Ansible 2.17)
+- SSH server enabled
+- Sudo access (if using `--use-sudo`)
+
+**⚠️ Known Issue: CentOS 8 / RHEL 8 with Python 3.6**
+
+On CentOS 8/RHEL 8, the system's `dnf` package manager may use Python 3.6
(`/usr/libexec/platform-python`), and the DNF Python module (`python3-dnf`) is
only available for Python 3.6, not for Python 3.9+.
+
+The installer works around this by using direct shell commands (e.g.,
`/usr/libexec/platform-python /usr/bin/dnf install`) for package installation
rather than Ansible's package module.
+
+#### Python Version Requirements by OS
+
+| Operating System | Default Python | Available Versions | Installation
Command |
+|-----------------|----------------|-------------------|---------------------|
+| RHEL 9+ / Rocky 9+ | Python 3.9+ ✅ | 3.11, 3.9 | `sudo yum install -y
python3.11` |
+| RHEL 8 / Rocky 8 / CentOS 8 | Python 3.6 ❌ | 3.9, 3.8 (python39, python38) |
`sudo yum install -y python39` |
+| CentOS 7 | Python 3.6 ❌ | 3.6 only | Must use EPEL or SCL for newer versions
|
+| Ubuntu 20.04+ | Python 3.8+ ✅ | 3.11, 3.10, 3.9, 3.8 | `sudo apt-get install
-y python3.11` |
+| Debian 11+ | Python 3.9+ ✅ | 3.11, 3.9 | `sudo apt-get install -y
python3.11` |
+
+**Important**: If your managed nodes have Python 3.6 or older, you must
upgrade:
+
+```bash
+# CentOS 8 / RHEL 8 / Rocky 8 (most common)
+sudo yum install -y python39
+# Verify: /usr/bin/python3.9 --version
+
+# RHEL 9+ / Rocky 9+
+sudo yum install -y python3.11
+# Verify: /usr/bin/python3.11 --version
+
+# Ubuntu / Debian
+sudo apt-get update && sudo apt-get install -y python3.9
+# Verify: /usr/bin/python3.9 --version
+```
+
+**Then specify the Python interpreter when running the installer:**
+```bash
+# For CentOS 8 / RHEL 8
+python3 ozone_installer.py -H hosts -v 2.0.0 --python-interpreter
/usr/bin/python3.9
+
+# For RHEL 9+
+python3 ozone_installer.py -H hosts -v 2.0.0 --python-interpreter
/usr/bin/python3.11
+```
+
+### Network and access requirements
+- Controller must be on the same network as the target hosts
+- Controller requires SSH access (key or password) to all target hosts
### Run on the controller node
```bash
@@ -70,17 +116,53 @@ python3 ozone_installer.py -H host1.domain -v 2.0.0
# HA upstream (3+ hosts) - mode auto-detected
python3 ozone_installer.py -H "host{1..3}.domain" -v 2.0.0
+# Using host file instead of CLI (one host per line, supports user@host:port
format)
+python3 ozone_installer.py -F hosts.txt -v 2.0.0
+
# Local snapshot build
python3 ozone_installer.py -H host1 -v local --local-path
/path/to/share/ozone-2.1.0-SNAPSHOT
# Cleanup and reinstall
python3 ozone_installer.py --clean -H "host{1..3}.domain" -v 2.0.0
+# Specify Python interpreter (if managed nodes have Python 3.6 or need
specific version)
+python3 ozone_installer.py -H "host{1..3}.domain" -v 2.0.0
--python-interpreter /usr/bin/python3.9
+
+# Verbose mode for debugging (passes -vvv to Ansible)
+python3 ozone_installer.py -H "host{1..3}.domain" -v 2.0.0 --verbose
+# OR with short flag
+python3 ozone_installer.py -H "host{1..3}.domain" -v 2.0.0 -V
+
# Notes on cleanup
# - During a normal install, you'll be asked whether to cleanup an existing
install (if present). Default is No.
# - Use --clean to cleanup without prompting before reinstall.
```
+### Python interpreter configuration
+
+The installer requires Python 3.7+ on managed nodes (Ansible 2.17 requirement).
+
+**You must configure the Python interpreter if your managed nodes don't have
Python 3.7+ as the default `/usr/bin/python3`.**
+
+**Via CLI (recommended):**
+```bash
+python3 ozone_installer.py -H hosts -v 2.0.0 --python-interpreter
/usr/bin/python3.9
+```
+
+**Via group_vars (for static inventory):**
+```yaml
+# inventories/dev/group_vars/all.yml
+ansible_python_interpreter: /usr/bin/python3.9 # or /usr/bin/python39 for
CentOS 8
+```
+
+**Via dynamic inventory:**
+Add `ansible_python_interpreter=/usr/bin/python3.9` to each host line in your
inventory.
+
+### Host file format
+
+When using `-F/--host-file`, create a text file with one host per line. See
`hosts.txt.example` for a complete example.
+
+
### Interactive prompts and version selection
- The installer uses `click` for interactive prompts when available (TTY).
- Version selection shows a numbered list; you can select by number, type a
specific version, or `local`.
@@ -100,6 +182,33 @@ ANSIBLE_CONFIG=ansible.cfg ansible-playbook -i
inventories/dev/hosts.ini playboo
--start-at-task "$(head -n1 logs/last_failed_task.txt)"
```
+### Debugging and Troubleshooting
+
+**Verbose Mode:** For detailed Ansible output (useful for debugging failures):
+
+```bash
+# Python wrapper - passes -vvv to Ansible
+python3 ozone_installer.py -H hosts -v 2.0.0 --verbose
+# OR with short flag
+python3 ozone_installer.py -H hosts -v 2.0.0 -V
+```
+
+The verbose flag provides:
+- Detailed task execution information
+- Variable values at each step
+- Full error tracebacks
+- SSH connection details
+- Module arguments and return values
+
+**Check Logs:**
+```bash
+# View the latest installer log
+tail -f logs/ansible-*.log
+
+# Check for task failures
+grep -i "fatal\|error" logs/ansible-*.log
+```
+
2) Direct Ansible (run playbooks yourself)
```bash
diff --git a/ansible.cfg b/ansible.cfg
index 44beba1..4378dc5 100644
--- a/ansible.cfg
+++ b/ansible.cfg
@@ -19,7 +19,8 @@ stdout_callback = default
retry_files_enabled = False
gathering = smart
forks = 20
-strategy = free
+strategy = linear
+; strategy = free for concurrent tasks
timeout = 30
roles_path = roles
log_path = logs/ansible.log
diff --git a/ansible.cfg b/hosts.txt.example
similarity index 53%
copy from ansible.cfg
copy to hosts.txt.example
index 44beba1..dcd13a8 100644
--- a/ansible.cfg
+++ b/hosts.txt.example
@@ -13,29 +13,29 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-[defaults]
-inventory = inventories/dev/hosts.ini
-stdout_callback = default
-retry_files_enabled = False
-gathering = smart
-forks = 20
-strategy = free
-timeout = 30
-roles_path = roles
-log_path = logs/ansible.log
-bin_ansible_callbacks = True
-callback_plugins = callback_plugins
-callbacks_enabled = timer, profile_tasks, last_failed ; for execution time
profiling and resume hints
-deprecation_warnings = False
-host_key_checking = False
-remote_tmp = /tmp/.ansible-${USER}
+# Example host file for ozone_installer.py
+# Usage: python3 ozone_installer.py -F hosts.txt.example -v 2.0.0
+#
+# Format: One host per line
+# Supports: user@host:port
+# Comments and empty lines are ignored
+
+# Simple hostname
+# host1.example.com
+
+# With SSH user
+# [email protected]
-[privilege_escalation]
-become = True
-become_method = sudo
+# With custom SSH port
+# host3.example.com:2222
-[ssh_connection]
-pipelining = True
-ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o
StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
+# Combined user and port
+# [email protected]:2222
+# For HA deployment (3+ hosts recommended)
+# host1.example.com
+# host2.example.com
+# host3.example.com
+# For Non-HA deployment (single host)
+# host1.example.com
diff --git a/inventories/dev/group_vars/all.yml
b/inventories/dev/group_vars/all.yml
index aae7150..31f7b9e 100644
--- a/inventories/dev/group_vars/all.yml
+++ b/inventories/dev/group_vars/all.yml
@@ -52,5 +52,3 @@ ssh_private_key_path: "" # optional path to private key
to copy for cluster
# Markers for profile management
JAVA_MARKER: "Apache Ozone Installer Java Home"
ENV_MARKER: "Apache Ozone Installer Env"
-
-
diff --git a/ozone_installer.py b/ozone_installer.py
index da0bd33..93c0084 100755
--- a/ozone_installer.py
+++ b/ozone_installer.py
@@ -79,6 +79,7 @@ def parse_args(argv: List[str]) -> argparse.Namespace:
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("-F", "--host-file", help="File containing target hosts
(one per line, supports @, : for user/port)")
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)")
@@ -98,6 +99,8 @@ def parse_args(argv: List[str]) -> argparse.Namespace:
# 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("--python-interpreter", help="Python interpreter for
managed nodes (e.g., /usr/bin/python3.9). If not specified, Ansible will
auto-detect.")
+ p.add_argument("--verbose", "-V", action="store_true", help="Verbose
output (passes -vvv to Ansible for detailed debugging)")
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)
@@ -293,12 +296,44 @@ def parse_hosts(hosts_raw: Optional[str]) -> List[dict]:
out.append({"host": host, "user": user, "port": port})
return out
+def read_hosts_from_file(filepath: str) -> Optional[str]:
+ """
+ Reads hosts from a file (one host per line).
+ Lines starting with # are treated as comments and ignored.
+ Empty lines are ignored.
+ Supports same format as CLI: user@host:port
+ Returns comma-separated host string suitable for parse_hosts().
+ """
+ logger = get_logger()
+ try:
+ path = Path(filepath)
+ if not path.exists():
+ logger.error(f"Host file not found: {filepath}")
+ return None
+ hosts = []
+ with path.open('r') as f:
+ for line in f:
+ line = line.strip()
+ # Skip empty lines and comments
+ if not line or line.startswith('#'):
+ continue
+ hosts.append(line)
+ if hosts:
+ logger.info(f"Read {len(hosts)} host(s) from {filepath}")
+ return ','.join(hosts)
+ else:
+ logger.error(f"No valid hosts found in {filepath}")
+ return None
+ except Exception as e:
+ logger.error(f"Error reading host file {filepath}: {e}")
+ return None
+
def auto_cluster_mode(hosts: List[dict], forced: Optional[str] = None) -> str:
if forced in ("non-ha", "ha"):
return forced
return "ha" if len(hosts) >= 3 else "non-ha"
-def build_inventory(hosts: List[dict], ssh_user: Optional[str] = None,
keyfile: Optional[str] = None, password: Optional[str] = None, cluster_mode:
str = "non-ha") -> str:
+def build_inventory(hosts: List[dict], ssh_user: Optional[str] = None,
keyfile: Optional[str] = None, password: Optional[str] = None, cluster_mode:
str = "non-ha", python_interpreter: Optional[str] = None) -> str:
"""
Returns INI inventory text for our groups: [om], [scm], [datanodes],
[recon], [s3g]
"""
@@ -309,7 +344,7 @@ def build_inventory(hosts: List[dict], ssh_user:
Optional[str] = None, keyfile:
h = hosts[0]
return _render_inv_groups(
om=[h], scm=[h], dn=hosts, recon=[h], s3g=[h],
- ssh_user=ssh_user, keyfile=keyfile, password=password
+ ssh_user=ssh_user, keyfile=keyfile, password=password,
python_interpreter=python_interpreter
)
# HA: first 3 go to OM and SCM; all to datanodes; recon is first if present
om = hosts[:3] if len(hosts) >= 3 else hosts
@@ -318,9 +353,9 @@ def build_inventory(hosts: List[dict], ssh_user:
Optional[str] = None, keyfile:
recon = [hosts[0]]
s3g = [hosts[0]]
return _render_inv_groups(om=om, scm=scm, dn=dn, recon=recon, s3g=s3g,
- ssh_user=ssh_user, keyfile=keyfile,
password=password)
+ ssh_user=ssh_user, keyfile=keyfile,
password=password, python_interpreter=python_interpreter)
-def _render_inv_groups(om: List[dict], scm: List[dict], dn: List[dict], recon:
List[dict], s3g: List[dict], ssh_user: Optional[str] = None, keyfile:
Optional[str] = None, password: Optional[str] = None) -> str:
+def _render_inv_groups(om: List[dict], scm: List[dict], dn: List[dict], recon:
List[dict], s3g: List[dict], ssh_user: Optional[str] = None, keyfile:
Optional[str] = None, password: Optional[str] = None, python_interpreter:
Optional[str] = None) -> str:
def hostline(hd):
parts = [hd["host"]]
if ssh_user or hd.get("user"):
@@ -331,6 +366,8 @@ def _render_inv_groups(om: List[dict], scm: List[dict], dn:
List[dict], recon: L
parts.append(f"ansible_ssh_private_key_file={shlex.quote(str(keyfile))}")
if password:
parts.append(f"ansible_password={shlex.quote(password)}")
+ if python_interpreter:
+ parts.append(f"ansible_python_interpreter={python_interpreter}")
return " ".join(parts)
sections = []
@@ -347,13 +384,15 @@ def _render_inv_groups(om: List[dict], scm: List[dict],
dn: List[dict], recon: L
sections.append("\n")
return "\n".join(sections)
-def run_playbook(playbook: Path, inventory_path: Path, extra_vars_path: Path,
ask_pass: bool = False, become: bool = True, start_at_task: Optional[str] =
None, tags: Optional[List[str]] = None) -> int:
+def run_playbook(playbook: Path, inventory_path: Path, extra_vars_path: Path,
ask_pass: bool = False, become: bool = True, start_at_task: Optional[str] =
None, tags: Optional[List[str]] = None, verbose: bool = False) -> int:
cmd = [
"ansible-playbook",
"-i", str(inventory_path),
str(playbook),
"-e", f"@{extra_vars_path}",
]
+ if verbose:
+ cmd.append("-vvv")
if ask_pass:
cmd.append("-k")
if become:
@@ -398,7 +437,15 @@ def main(argv: List[str]) -> int:
# Gather inputs interactively where missing
hosts_raw_default = (last_cfg.get("hosts_raw") if last_cfg else None)
- hosts_raw = args.host or hosts_raw_default or prompt("Target host(s)
[non-ha: host | HA: h1,h2,h3 or brace expansion]", default="", yes_mode=yes)
+ # Check if hosts are provided via file first, then CLI, then default/prompt
+ if args.host_file:
+ hosts_raw = read_hosts_from_file(args.host_file)
+ if not hosts_raw:
+ logger = get_logger()
+ logger.error(f"Error: Could not read hosts from file:
{args.host_file}")
+ return 2
+ else:
+ hosts_raw = args.host or hosts_raw_default or prompt("Target host(s)
[non-ha: host | HA: h1,h2,h3 or brace expansion]", default="", yes_mode=yes)
hosts = parse_hosts(hosts_raw) if hosts_raw else []
# Initialize per-run logger as soon as we have hosts_raw
try:
@@ -414,7 +461,7 @@ def main(argv: List[str]) -> int:
logger.info(f"Logging to: {run_log_path} (fallback)")
if not hosts:
- logger.error("Error: No hosts provided (-H/--host).")
+ logger.error("Error: No hosts provided (-H/--host or -F/--host-file).")
return 2
# Decide HA vs Non-HA with user input; default depends on host count
resume_cluster_mode = (last_cfg.get("cluster_mode") if last_cfg else None)
@@ -424,7 +471,7 @@ def main(argv: List[str]) -> int:
cluster_mode = resume_cluster_mode
else:
default_mode = "ha" if len(hosts) >= 3 else "non-ha"
- selected = prompt("Deployment type (ha|non-ha)", default=default_mode,
yes_mode=yes)
+ selected = prompt("Deployment type (option: ha or non-ha)",
default=default_mode, yes_mode=yes)
cluster_mode = (selected or default_mode).strip().lower()
if cluster_mode not in ("ha", "non-ha"):
cluster_mode = default_mode
@@ -446,19 +493,19 @@ def main(argv: List[str]) -> int:
ozone_version = prompt("Ozone version (e.g., 2.1.0 | local)",
default=DEFAULTS["ozone_version"], yes_mode=yes)
jdk_major = args.jdk_version if args.jdk_version is not None else
((last_cfg.get("jdk_major") if last_cfg else None))
if jdk_major is None:
- _jdk_val = prompt("JDK major (17|21)",
default=str(DEFAULTS["jdk_major"]), yes_mode=yes)
+ _jdk_val = prompt("JDK major (option: 17 or 21)",
default=str(DEFAULTS["jdk_major"]), yes_mode=yes)
try:
jdk_major = int(str(_jdk_val)) if _jdk_val is not None else
DEFAULTS["jdk_major"]
except Exception:
jdk_major = DEFAULTS["jdk_major"]
install_base = args.install_dir or (last_cfg.get("install_base") if
last_cfg else None) \
- or prompt("Install base directory (binaries and configs; e.g.,
/opt/ozone)", default=DEFAULTS["install_base"], yes_mode=yes)
+ or prompt("Install directory (base directory path to store ozone
binaries, configs and logs)", default=DEFAULTS["install_base"], yes_mode=yes)
data_base = args.data_dir or (last_cfg.get("data_base") if last_cfg else
None) \
- or prompt("Data base directory (metadata and DN data; e.g.,
/data/ozone)", default=DEFAULTS["data_base"], yes_mode=yes)
+ or prompt("Data directory (base directory path to store ozone metadata
and data)", default=DEFAULTS["data_base"], yes_mode=yes)
# Auth (before service user/group)
auth_method = args.auth_method or (last_cfg.get("auth_method") if last_cfg
else None) \
- or prompt("Auth method (key|password)", default="password",
yes_mode=yes)
+ or prompt("SSH authentication method (option: key or password)",
default="password", yes_mode=yes)
if auth_method not in ("key", "password"):
auth_method = "password"
ssh_user = args.ssh_user or (last_cfg.get("ssh_user") if last_cfg else
None) \
@@ -475,9 +522,9 @@ def main(argv: List[str]) -> int:
elif auth_method == "key":
password = None
service_user = args.service_user or (last_cfg.get("service_user") if
last_cfg else None) \
- or prompt("Service user", default=DEFAULTS["service_user"],
yes_mode=yes)
+ or prompt("Service user name ", default=DEFAULTS["service_user"],
yes_mode=yes)
service_group = args.service_group or (last_cfg.get("service_group") if
last_cfg else None) \
- or prompt("Service group", default=DEFAULTS["service_group"],
yes_mode=yes)
+ or prompt("Service group name", default=DEFAULTS["service_group"],
yes_mode=yes)
dl_url = args.dl_url or (last_cfg.get("dl_url") if last_cfg else None) or
DEFAULTS["dl_url"]
start_after_install = (args.start or (last_cfg.get("start_after_install")
if last_cfg else None)
or DEFAULTS["start_after_install"])
@@ -527,10 +574,10 @@ def main(argv: List[str]) -> int:
("Cluster mode", cluster_mode),
("Ozone version", str(ozone_version)),
("JDK major", str(jdk_major)),
- ("Install base", str(install_base)),
- ("Data base", str(data_base)),
+ ("Install directory", str(install_base)),
+ ("Data directory", str(data_base)),
("SSH user", str(ssh_user)),
- ("Auth method", str(auth_method))
+ ("SSH auth method", str(auth_method))
]
if keyfile:
summary_rows.append(("Key file", str(keyfile)))
@@ -544,9 +591,16 @@ def main(argv: List[str]) -> int:
logger.info("Aborted by user.")
return 1
+ # Python interpreter (optional, auto-detected if not provided)
+ python_interpreter = args.python_interpreter or
(last_cfg.get("python_interpreter") if last_cfg else None)
+ if python_interpreter:
+ logger.info(f"Using Python interpreter: {python_interpreter}")
+ else:
+ logger.info("Python interpreter will be auto-detected by playbook")
+
# Prepare dynamic inventory and extra-vars
inventory_text = build_inventory(hosts, ssh_user=ssh_user,
keyfile=keyfile, password=password,
- cluster_mode=cluster_mode)
+ cluster_mode=cluster_mode,
python_interpreter=python_interpreter)
# Decide cleanup behavior up-front (so we can pass it into the unified
play)
do_cleanup = False
if args.clean:
@@ -572,6 +626,10 @@ def main(argv: List[str]) -> int:
"ENV_MARKER": DEFAULTS["ENV_MARKER"],
"controller_logs_dir": str(LOGS_DIR),
}
+ # Add Python interpreter if explicitly specified by user
+ if python_interpreter:
+ extra_vars["ansible_python_interpreter"] = python_interpreter
+ extra_vars["ansible_python_interpreter_discovery"] = "explicit"
if ozone_version and ozone_version.lower() == "local":
extra_vars.update({
"local_shared_path": local_shared_path or "",
@@ -615,6 +673,7 @@ def main(argv: List[str]) -> int:
"use_sudo": bool(use_sudo),
"local_shared_path": local_shared_path or "",
"local_ozone_dirname": local_oz_dir or "",
+ "python_interpreter": python_interpreter or "",
}, indent=2), encoding="utf-8")
except Exception:
# Fall back to temp files if persisting fails
@@ -639,7 +698,7 @@ def main(argv: List[str]) -> int:
use_tags = [role_name]
except Exception:
start_at = None
- rc = run_playbook(playbook, inv_path, ev_path, ask_pass=ask_pass,
become=True, start_at_task=start_at, tags=use_tags)
+ rc = run_playbook(playbook, inv_path, ev_path, ask_pass=ask_pass,
become=True, start_at_task=start_at, tags=use_tags, verbose=args.verbose)
if rc != 0:
return rc
diff --git a/playbooks/cluster.yml b/playbooks/cluster.yml
index 9e6da01..bef59f4 100644
--- a/playbooks/cluster.yml
+++ b/playbooks/cluster.yml
@@ -22,17 +22,6 @@
cluster_mode: "{{ cluster_mode | default('non-ha') }}"
ha_enabled: "{{ cluster_mode == 'ha' }}"
pre_tasks:
- - name: "Pre-install: Ensure python3 present"
- raw: |
- if command -v apt-get >/dev/null 2>&1; then sudo -n apt-get update -y
&& sudo -n apt-get install -y python3 || true;
- elif command -v dnf >/dev/null 2>&1; then sudo -n dnf install -y
python3 || true;
- elif command -v yum >/dev/null 2>&1; then sudo -n yum install -y
python3 || true;
- elif command -v zypper >/dev/null 2>&1; then sudo -n zypper
--non-interactive in -y python3 || true;
- fi
- args:
- executable: /bin/bash
- changed_when: false
- failed_when: false
- name: "Pre-install: Gather facts"
setup:
@@ -72,3 +61,53 @@
tags: ["ozone_ui"]
- role: ozone_smoke
tags: ["ozone_smoke"]
+
+ post_tasks:
+ - name: "Build UI endpoints display lines"
+ set_fact:
+ ui_display_lines: >-
+ {{
+ [
+ '',
+ '==========================================',
+ ' Ozone Cluster UI Endpoints',
+ '==========================================',
+ '',
+ 'OM UI:'
+ ] +
+ (endpoint_urls.om | map('regex_replace', '^', ' - ') | list) +
+ ['', 'SCM UI:'] +
+ (endpoint_urls.scm | map('regex_replace', '^', ' - ') | list) +
+ ['', 'Recon UI:'] +
+ ((endpoint_urls.recon | length > 0) | ternary(
+ endpoint_urls.recon | map('regex_replace', '^', ' - ') | list,
+ [' - Not configured']
+ )) +
+ ['', 'S3 Gateway (HTTP):'] +
+ ((endpoint_urls.s3g_http | length > 0) | ternary(
+ endpoint_urls.s3g_http | map('regex_replace', '^', ' - ') |
list,
+ [' - Not configured']
+ )) +
+ ['', 'S3 Gateway (Admin):'] +
+ ((endpoint_urls.s3g_admin | length > 0) | ternary(
+ endpoint_urls.s3g_admin | map('regex_replace', '^', ' - ') |
list,
+ [' - Not configured']
+ )) +
+ [
+ '',
+ '==========================================',
+ 'UI endpoints also saved to: ' ~ (controller_logs_dir |
default('logs')) ~ '/endpoint_urls.json',
+ '==========================================',
+ ''
+ ]
+ }}
+ run_once: true
+ when: endpoint_urls is defined
+ tags: ["always"]
+
+ - name: "Display UI Endpoints Summary"
+ debug:
+ msg: "{{ ui_display_lines }}"
+ run_once: true
+ when: endpoint_urls is defined
+ tags: ["always"]
diff --git a/roles/cleanup/tasks/main.yml b/roles/cleanup/tasks/main.yml
index 7180288..5d41c8f 100644
--- a/roles/cleanup/tasks/main.yml
+++ b/roles/cleanup/tasks/main.yml
@@ -52,13 +52,13 @@
loop_control:
label: "{{ item }}"
- - name: "Remove install base"
+ - name: "Remove install directory"
file:
path: "{{ install_base }}"
state: absent
become: true
- - name: "Remove data base"
+ - name: "Remove data directory"
file:
path: "{{ data_base }}"
state: absent
diff --git a/roles/java/tasks/main.yml b/roles/java/tasks/main.yml
index d5f07b2..8d95654 100644
--- a/roles/java/tasks/main.yml
+++ b/roles/java/tasks/main.yml
@@ -59,6 +59,7 @@
become: false
vars:
last_vars_path: "{{ playbook_dir }}/../logs/last_vars.json"
+ ansible_python_interpreter: "{{ ansible_playbook_python }}"
block:
- name: "last_vars.json | Read"
slurp:
diff --git a/roles/ozone_fetch/tasks/main.yml b/roles/ozone_fetch/tasks/main.yml
index 40588c1..b4f2b24 100644
--- a/roles/ozone_fetch/tasks/main.yml
+++ b/roles/ozone_fetch/tasks/main.yml
@@ -84,6 +84,7 @@
become: false
vars:
ansible_become: false
+ ansible_python_interpreter: "{{ ansible_playbook_python }}"
command:
argv:
- tar
@@ -122,6 +123,7 @@
become: false
vars:
ansible_become: false
+ ansible_python_interpreter: "{{ ansible_playbook_python }}"
file:
path: "/tmp/{{ local_ozone_dirname }}.tar.gz"
state: absent
diff --git a/roles/ozone_ui/tasks/main.yml b/roles/ozone_ui/tasks/main.yml
index f17b2af..692550b 100644
--- a/roles/ozone_ui/tasks/main.yml
+++ b/roles/ozone_ui/tasks/main.yml
@@ -14,34 +14,30 @@
# limitations under the License.
## Print and export service UI endpoints
-- name: "Compute service UI URLs"
+- name: "Get host lists for UI endpoints"
set_fact:
_om_hosts_ui: "{{ groups.get('om', []) | list }}"
_scm_hosts_ui: "{{ groups.get('scm', []) | list }}"
_recon_hosts_ui: "{{ groups.get('recon', []) | list }}"
_s3g_hosts_ui: "{{ groups.get('s3g', []) | list }}"
- ui_urls:
+
+- name: "Compute service UI URLs"
+ set_fact:
+ endpoint_urls:
om: "{{ _om_hosts_ui | map('regex_replace','^(.*)$','http://\\1:9874') |
list }}"
scm: "{{ _scm_hosts_ui | map('regex_replace','^(.*)$','http://\\1:9876')
| list }}"
recon: "{{ (_recon_hosts_ui | length > 0) | ternary(['http://' +
_recon_hosts_ui[0] + ':9888'], []) }}"
s3g_http: "{{ _s3g_hosts_ui |
map('regex_replace','^(.*)$','http://\\1:9878') | list }}"
s3g_admin: "{{ _s3g_hosts_ui |
map('regex_replace','^(.*)$','http://\\1:19878') | list }}"
-- name: "Service UI Endpoints"
- debug:
- msg:
- - "OM UI: {{ ui_urls.om }}"
- - "SCM UI: {{ ui_urls.scm }}"
- - "Recon UI: {{ ui_urls.recon }}"
- - "S3G HTTP: {{ ui_urls.s3g_http }}"
- - "S3G Admin: {{ ui_urls.s3g_admin }}"
- run_once: true
-
- name: "Export UI endpoints to controller logs directory"
copy:
- content: "{{ ui_urls | to_nice_json }}"
- dest: "{{ controller_logs_dir }}/ui_urls.json"
+ content: "{{ endpoint_urls | to_nice_json }}"
+ dest: "{{ controller_logs_dir }}/endpoint_urls.json"
mode: "0644"
delegate_to: localhost
+ become: false
run_once: true
- when: controller_logs_dir is defined
\ No newline at end of file
+ when: controller_logs_dir is defined
+ vars:
+ ansible_python_interpreter: "{{ ansible_playbook_python }}"
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]