<reponame>cseelye/sfauto
#!/usr/bin/env python

"""
This action will discover nodes in a subnet
"""

from libsf.apputil import PythonApp
from libsf.argutil import SFArgumentParser, GetFirstLine, SFArgFormatter
from libsf.logutil import GetLogger, logargs, SetThreadLogPrefix
from libsf.util import ValidateAndDefault, IPv4SubnetType
from libsf import threadutil
from libsf.netutil import IPSubnet
from libsf import SolidFireNodeAPI
from libsf import SolidFireError, UnauthorizedError
import socket

@logargs
@ValidateAndDefault({
    # "arg_name" : (arg_type, arg_default)
    "subnet": (IPv4SubnetType, None),
})
def NodeDiscoverSubnet(subnet):
    """
    Discover nodes in a subnet

    Args:
        subnet:     the subnet to search, in CIDR or network/netmask
    """
    log = GetLogger()

    all_ips = IPSubnet(subnet).AllHosts()
    log.info("Searching {} IPs for nodes...".format(len(all_ips)))

    pool = threadutil.ThreadPool(64)
    results = []
    for idx, node_ip in enumerate(all_ips):
        results.append(pool.Post(_NodeThread, node_ip))

    found = 0
    for idx, node_ip in enumerate(all_ips):
        try:
            node_info = results[idx].Get()
            if node_info:
                log.info("  {:15}  version {:11}  {}{}{}".format(node_ip,
                                                               node_info["version"],
                                                               node_info["state"],
                                                               " cluster " if node_info["state"] != "Available" else "",
                                                               node_info["cluster"] if node_info["state"] != "Available" else ""))
                found += 1
        except SolidFireError as ex:
            log.error("{}: {}".format(node_ip, str(ex)))

    log.info("Found {} nodes".format(found))
    return True

@threadutil.threadwrapper
def _NodeThread(node_ip):
    """Check if this IP is a node"""
    log = GetLogger()
    SetThreadLogPrefix(node_ip)

    known_auth = [
        ("admin", "admin"),
        ("admin", "solidfire")
    ]

    SFCONFIG_PORT = 442

    sock = socket.socket()
    sock.settimeout(0.5)
    try:
        sock.connect((node_ip, SFCONFIG_PORT))
        sock.close()
        log.debug("Port {} socket connect succeeded".format(SFCONFIG_PORT))
    except (socket.timeout, socket.error, socket.herror, socket.gaierror):
        # If sfconfig is not running, this does not look like a node
        return None

    node_info = {}
    for user, passwd in known_auth:
        api = SolidFireNodeAPI(node_ip, user, passwd, maxRetryCount=0)
        try:
            result = api.Call("GetClusterConfig", {}, timeout=2)
            node_info["cluster"] = result["cluster"]["cluster"]
            node_info["name"] = result["cluster"]["name"]
            node_info["state"] = result["cluster"]["state"]
            if "version" in result["cluster"]:
                node_info["version"] = result["cluster"]["version"]
            else:
                result = api.Call("GetVersionInfo", {}, timeout=6)
                node_info["version"] = result["versionInfo"]["sfconfig"]["Version"]
            break
        except UnauthorizedError:
            continue
        except SolidFireError as ex:
            log.debug(str(ex))
            return None

    if not node_info:
        return None

    if not node_info["cluster"]:
        node_info["cluster"] = "Available"

    return node_info


if __name__ == '__main__':
    parser = SFArgumentParser(description=GetFirstLine(__doc__), formatter_class=SFArgFormatter)
    parser.add_argument("--subnet", type=IPv4SubnetType, required=True, help="The subnet to search, in either CIDR or network/netmask format")
    args = parser.parse_args_to_dict()

    app = PythonApp(NodeDiscoverSubnet, args)
    app.Run(**args)

#!/usr/bin/env python

"""
This action will discover nodes in a subnet
"""

from libsf.apputil import PythonApp
from libsf.argutil import SFArgumentParser, GetFirstLine, SFArgFormatter
from libsf.logutil import GetLogger, logargs, SetThreadLogPrefix
from libsf.util import ValidateAndDefault, IPv4SubnetType
from libsf import threadutil
from libsf.netutil import IPSubnet
from libsf import SolidFireNodeAPI
from libsf import SolidFireError, UnauthorizedError
import socket

@logargs
@ValidateAndDefault({
    # "arg_name" : (arg_type, arg_default)
    "subnet": (IPv4SubnetType, None),
})
def NodeDiscoverSubnet(subnet):
    """
    Discover nodes in a subnet

    Args:
        subnet:     the subnet to search, in CIDR or network/netmask
    """
    log = GetLogger()

    all_ips = IPSubnet(subnet).AllHosts()
    log.info("Searching {} IPs for nodes...".format(len(all_ips)))

    pool = threadutil.ThreadPool(64)
    results = []
    for idx, node_ip in enumerate(all_ips):
        results.append(pool.Post(_NodeThread, node_ip))

    found = 0
    for idx, node_ip in enumerate(all_ips):
        try:
            node_info = results[idx].Get()
            if node_info:
                log.info("  {:15}  version {:11}  {}{}{}".format(node_ip,
                                                               node_info["version"],
                                                               node_info["state"],
                                                               " cluster " if node_info["state"] != "Available" else "",
                                                               node_info["cluster"] if node_info["state"] != "Available" else ""))
                found += 1
        except SolidFireError as ex:
            log.error("{}: {}".format(node_ip, str(ex)))

    log.info("Found {} nodes".format(found))
    return True

@threadutil.threadwrapper
def _NodeThread(node_ip):
    """Check if this IP is a node"""
    log = GetLogger()
    SetThreadLogPrefix(node_ip)

    known_auth = [
        ("admin", "admin"),
        ("admin", "solidfire")
    ]

    SFCONFIG_PORT = 442

    sock = socket.socket()
    sock.settimeout(0.5)
    try:
        sock.connect((node_ip, SFCONFIG_PORT))
        sock.close()
        log.debug("Port {} socket connect succeeded".format(SFCONFIG_PORT))
    except (socket.timeout, socket.error, socket.herror, socket.gaierror):
        # If sfconfig is not running, this does not look like a node
        return None

    node_info = {}
    for user, passwd in known_auth:
        api = SolidFireNodeAPI(node_ip, user, passwd, maxRetryCount=0)
        try:
            result = api.Call("GetClusterConfig", {}, timeout=2)
            node_info["cluster"] = result["cluster"]["cluster"]
            node_info["name"] = result["cluster"]["name"]
            node_info["state"] = result["cluster"]["state"]
            if "version" in result["cluster"]:
                node_info["version"] = result["cluster"]["version"]
            else:
                result = api.Call("GetVersionInfo", {}, timeout=6)
                node_info["version"] = result["versionInfo"]["sfconfig"]["Version"]
            break
        except UnauthorizedError:
            continue
        except SolidFireError as ex:
            log.debug(str(ex))
            return None

    if not node_info:
        return None

    if not node_info["cluster"]:
        node_info["cluster"] = "Available"

    return node_info


if __name__ == '__main__':
    parser = SFArgumentParser(description=GetFirstLine(__doc__), formatter_class=SFArgFormatter)
    parser.add_argument("--subnet", type=IPv4SubnetType, required=True, help="The subnet to search, in either CIDR or network/netmask format")
    args = parser.parse_args_to_dict()

    app = PythonApp(NodeDiscoverSubnet, args)
    app.Run(**args)
#!/usr/bin/env python This action will discover nodes in a subnet # "arg_name" : (arg_type, arg_default) Discover nodes in a subnet      Args:         subnet:     the subnet to search, in CIDR or network/netmask Check if this IP is a node # If sfconfig is not running, this does not look like a node