#!/usr/bin/env python3
import argparse
import configparser
import os
import subprocess
import sys
import datetime

# Examples:
#   ./ipmi_multipoweron.py host1 host2 host3
#   ./ipmi_multipoweron.py host1 host2 host3 -c /path/to/credentials
#   ./ipmi_multipoweron.py -f serverlist.txt
#   ./ipmi_multipoweron.py -f serverlist.txt -c /path/to/credentials

def ts_print(msg):
    """Print message prefixed with a timestamp (YYYY-MM-DD HH:MM:SS)."""
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"[{now}] {msg}")

DEFAULT_EK = "0000000000000000000000000000000000000000"


def find_credentials_file(provided_path):
    """Find credentials file in standard locations if provided path doesn't exist."""
    # If provided path exists, use it
    if os.path.exists(provided_path):
        return provided_path
    
    # Check standard locations
    standard_paths = [
        os.path.expanduser("~/credentials"),
        "/etc/credentials",
    ]
    
    for path in standard_paths:
        if os.path.exists(path):
            return path
    
    # Return the provided path (will fail with proper error message later)
    return provided_path


def load_credentials(path):
    cred_path = find_credentials_file(path)
    
    if not os.path.exists(cred_path):
        ts_print(f"Error: credentials file not found: {cred_path}")
        sys.exit(1)

    config = configparser.ConfigParser()
    config.read(cred_path)

    try:
        username = config.get("credentials", "username", fallback="root")
        password = config.get("credentials", "password")
        encryption_key = config.get("credentials", "encryption_key", fallback=DEFAULT_EK)
    except (configparser.NoSectionError, configparser.NoOptionError) as e:
        ts_print(f"Error reading credentials file: {e}")
        sys.exit(1)

    return username, password, encryption_key


def power_on_host(host, ipmi_user, ipmi_pw, ipmi_ek):
    """Power on a single host via IPMI. Returns True if successful."""
    cmd = [
        "ipmitool",
        "-I", "lanplus",
        "-H", host,
        "-U", ipmi_user,
        "-P", ipmi_pw,
        "-y", ipmi_ek,
        "power", "on",
    ]
    
    proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    if proc.returncode != 0:
        ts_print(f"ERROR: Failed to power on {host}: {proc.stderr.strip()}")
        return False
    else:
        ts_print(f"SUCCESS: {host} - {proc.stdout.strip()}")
        return True


def load_servers_from_file(filepath):
    """Load server list from a file (one server per line, lines starting with # are ignored)."""
    if not os.path.exists(filepath):
        ts_print(f"Error: server list file not found: {filepath}")
        sys.exit(1)
    
    servers = []
    try:
        with open(filepath, 'r') as f:
            for line in f:
                line = line.strip()
                # Skip empty lines and comments
                if line and not line.startswith('#'):
                    servers.append(line)
    except Exception as e:
        ts_print(f"Error reading server list file: {e}")
        sys.exit(1)
    
    return servers


def main():
    p = argparse.ArgumentParser(description="Send IPMI power on to multiple servers")
    
    # Either provide servers as arguments or a file
    group = p.add_mutually_exclusive_group(required=True)
    group.add_argument(
        "servers",
        nargs="*",
        help="List of IPMI host addresses (space-separated)"
    )
    group.add_argument(
        "-f", "--file",
        help="Path to file containing list of servers (one per line)"
    )
    
    p.add_argument(
        "-c",
        "--credentials",
        default="credentials",
        help="Path to credentials file (default: credentials; also checks ~/ and /etc/ if not found)",
    )
    args = p.parse_args()

    # Determine server list
    if args.file:
        servers = load_servers_from_file(args.file)
    else:
        servers = args.servers
    
    if not servers:
        ts_print("Error: No servers specified")
        sys.exit(1)
    
    ts_print(f"Starting power on sequence for {len(servers)} server(s)")
    
    ipmi_user, ipmi_pw, ipmi_ek = load_credentials(args.credentials)
    
    success_count = 0
    failed_count = 0
    
    for host in servers:
        if power_on_host(host, ipmi_user, ipmi_pw, ipmi_ek):
            success_count += 1
        else:
            failed_count += 1
    
    ts_print(f"Completed: {success_count} successful, {failed_count} failed")
    
    if failed_count > 0:
        sys.exit(1)


if __name__ == "__main__":
    main()
