#!/usr/bin/python
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

 


import sys, os, subprocess, errno, re
from os.path import exists

TOOl_PATH = "/usr/bin/ipmitool"

try:
    from subprocess import check_call
    from subprocess import CalledProcessError
except ImportError:
    def check_call(*popenargs, **kwargs):
        import subprocess
        retcode = subprocess.call(*popenargs, **kwargs)
        cmd = kwargs.get("args")
        if cmd is None: cmd = popenargs[0]
        if retcode: raise CalledProcessError(retcode, cmd)
        return retcode

    class CalledProcessError(Exception):
        def __init__(self, returncode, cmd):
            self.returncode = returncode ; self.cmd = cmd
        def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)

class Command:
    def __init__(self,name,parent=None):
        self.__name = name
        self.__parent = parent
    def __getattr__(self,name):
        if name == "_print": name = "print"
        return Command(name,self)
    def __call__(self,*args):
        class CommandOutput:
            def __init__(self,ret,stdout,stderr):
                self.stdout = stdout
                self.stderr = stderr
                self.ret = ret

        cmd = self.__get_recursive_name() + list(args)
        #print "    ",cmd
        popen = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        m = popen.communicate()
        ret = popen.wait()
        return CommandOutput(ret,*m)
    def __get_recursive_name(self,sep=None):
        m = self
        l = []
        while m is not None:
            l.append(m.__name)
            m = m.__parent
        l.reverse()
        if sep: return sep.join(l)
        else: return l
    def __str__(self):
        return '<Command %r>'%self.__get_recursive_name(sep=" ")
        
    def __repr__(self): return self.__str__()


ipmitool = Command("ipmitool")

def check_tool():
    if exists(TOOl_PATH) == False:
        print "Can not find ipmitool"
        return False

def addInterfaceOption(cmd, args):
    iface = args.get("interface")
    if not iface or iface == "default":
        return cmd

    cmd.insert(0, iface)
    cmd.insert(0, "-I")
    return cmd

def ping(args):
    hostname = args.get("hostname")
    usrname = args.get("usrname")
    password = args.get("password")

    if hostname == None:
        print "No hostname"
        return 1

    o = ipmitool(*addInterfaceOption(["-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "status"], args))
    if o.ret:
        print o.stderr
        return 1
    else:
        print o.stdout
        return 0

def boot_dev(args):
    hostname = args.get("hostname")
    usrname = args.get("usrname")
    password = args.get("password")
    dev = args.get("dev")

    if hostname == None:
        print "No hostname"
        return 1

    if dev == None:
        print "No boot device specified"
        return 1

    o = ipmitool(*addInterfaceOption(["-H", hostname, "-U", usrname, "-P", password, "chassis", "bootdev", dev], args))
    if o.ret:
        print o.stderr
        return 1
    else:
        return 0

def reboot(args):
    hostname = args.get("hostname")
    usrname = args.get("usrname")
    password = args.get("password")

    if hostname == None:
        print "No hostname"
        return 1

    o = ipmitool(*addInterfaceOption(["-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "status"], args))
    if o.ret:
        print o.stderr
        return 1
    

    if "is on" in o.stdout:
        o = ipmitool(*addInterfaceOption(["-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "cycle"], args))
    else:
        o = ipmitool(*addInterfaceOption(["-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "reset"], args))
        
    if o.ret:
        print o.stderr
        return 1
    else:
        return 0

def power(args):
    hostname = args.get("hostname")
    usrname = args.get("usrname")
    password = args.get("password")
    action = args.get("action")

    if hostname == None:
        print "No hostname"
        return 1

    o = ipmitool(*addInterfaceOption(["-H", hostname, "-U", usrname, "-P", password, "chassis", "power", action], args))
    if o.ret:
        print o.stderr
        return 1
    else:
        return 0

def boot_or_reboot(args):
    hostname = args.get("hostname")
    usrname = args.get("usrname")
    password = args.get("password")
    o = ipmitool(*addInterfaceOption(["-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "status"], args))
    if o.ret:
        print o.stderr
        return 1
    
    if "is on" in o.stdout:
        return reboot(args)
    elif "is off" in o.stdout:
        args["action"] = "on"
        return power(args)
    else:
        print "unknown power status:" + o.stdout
        return 1
    

call_table = {"ping":ping, "boot_dev":boot_dev, "reboot":reboot, "power":power, "boot_or_reboot":boot_or_reboot}
def dispatch(args):
    cmd = args[1]
    params = args[2:]
    func_params = {}

    if call_table.has_key(cmd) == False:
        print "No function %s" % cmd
        return 1

    for p in params:
        pairs = p.split("=")
        if len(pairs) != 2:
            print "Invalid parameter %s" % p
            return 1
        func_params[pairs[0]] = pairs[1]

    func = call_table[cmd]
    return func(func_params)

if __name__ == "__main__":
    if check_tool() == False:
        sys.exit(1)
    if len(sys.argv) < 2:
        print "Not enough arguments, at least one"
        sys.exit(1)
    sys.exit(dispatch(sys.argv))
