<?php

function hardware_profile_load_machine($con, $conf, $machine_id){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $n = mysqli_num_rows($r);
    if($n < 1){
        $json["status"] = "error";
        $json["message"] = "Cannot find a machine with id $machine_id.";
        return $json;
    }
    $machine = mysqli_fetch_array($r);

    # Fetch all block devices behind RAID controllers
    $q = "SELECT * FROM physblockdevices WHERE machine_id='$machine_id' ORDER BY slot";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $n = mysqli_num_rows($r);
    if($n >= 1){
        $machine["physbd"] = Array();
        for($i=0;$i<$n;$i++){
            $machine["physbd"][] = mysqli_fetch_array($r);
        }
    }

    # Fetch all block devices
    $q = "SELECT * FROM blockdevices WHERE machine_id='$machine_id'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $n = mysqli_num_rows($r);
    if($n >= 1){
        $machine["bd"] = Array();
        for($i=0;$i<$n;$i++){
            $machine["bd"][] = mysqli_fetch_array($r);
        }
    }

    if(isset($machine["physbd"])){
        $machine["controller_type"] = "megacli";
        $machine["hdds"] = $machine["physbd"];
    }else{
        $machine["controller_type"] = "none";
        if(isset($machine["bd"])){
            $machine["hdds"] = $machine["bd"];
        }
    }
    $json["data"] = $machine;
    return $json;
}

function hardware_profile_load_profile($con, $conf, $profile_name){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";


    $json_file = file_get_contents("/etc/openstack-cluster-installer/hardware-profiles.json");
    if($json_file === FALSE){
        $json["status"] = "error";
        $json["message"] = "Cannot load /etc/openstack-cluster-installer/hardware-profiles.json.";
        return $json;
    }
    $profiles = json_decode($json_file, TRUE);
    if($profiles === FALSE || $profiles === NULL){
        $json["status"] = "error";
        $json["message"] = "Cannot decode /etc/openstack-cluster-installer/hardware-profiles.json.";
        return $json;
    }

    if(!isset($profiles[$profile_name])){
        $json["status"] = "error";
        $json["message"] = "Profile $profile_name doesn't exist.";
        return $json;
    }

    $json["data"] = $profiles[$profile_name];
    return $json;
}

function hardware_profile_guess_profile($con, $conf, $machine_id, $debug="no"){
    if($debug == "no"){
        $debug_profile_matcher = "no";
    }else{
        $debug_profile_matcher = "yes";
    }
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";
    $json["data"] = Array();

    $ret = hardware_profile_load_machine($con, $conf, $machine_id);
    if($ret["status"] != "success"){
        return $ret;
    }
    $machine = $ret["data"];

    $json_file = file_get_contents("/etc/openstack-cluster-installer/hardware-profiles.json");
    if($json_file === FALSE){
        $json["status"] = "error";
        $json["message"] = "Cannot load /etc/openstack-cluster-installer/hardware-profiles.json.";
        return $json;
    }
    $profiles = json_decode($json_file, TRUE);
    if($profiles === FALSE || $profiles === NULL){
        $json["status"] = "error";
        $json["message"] = "Cannot decode /etc/openstack-cluster-installer/hardware-profiles.json.";
        return $json;
    }

    # Filter on product names
    $new_profiles = Array();
    $profile_names = array_keys($profiles);
    $machine_product_name = $machine["product_name"];
    foreach($profile_names as &$profile_name){
        $product_names = $profiles[$profile_name]["product-name"];
        $has_match = "no";
        foreach($product_names as &$product_name){
            if($product_name == $machine_product_name){
                $has_match = "yes";
            }
        }
        if($has_match == "yes"){
            $new_profiles[$profile_name] = $profiles[$profile_name];
        }else{
            if($debug_profile_matcher == "yes"){
                $json["data"][] = "Filtering $profile_name: product name does not match.";
//                print("Filtering $profile_name: product name does not match.\n");
            }
        }
    }
    $profiles = $new_profiles;

    # Filter on RAM amount
    $new_profiles = Array();
    $profile_names = array_keys($profiles);
    $machine_memory = $machine["memory"] / 1024;
    foreach($profile_names as &$profile_name){ 
        $profile_min_mem = $profiles[$profile_name]["ram"]["min"];
        $profile_max_mem = $profiles[$profile_name]["ram"]["max"];
        if($profile_min_mem <= $machine_memory && $profile_max_mem >= $machine_memory){
            $new_profiles[$profile_name] = $profiles[$profile_name];
        }else{
            if($debug_profile_matcher == "yes"){
                $json["data"][] = "Filtering $profile_name: RAM amount does not match.";
//                print("Filtering $profile_name: RAM amount does not match.\n");
            }
        }
    }
    $profiles = $new_profiles;

    # Filter on existance of RAID controller
    $new_profiles = Array();
    $profile_names = array_keys($profiles);
    foreach($profile_names as &$profile_name){
        $profile_controller_type = $profiles[$profile_name]["hdd"]["controller"];
        if($profile_controller_type != $machine["controller_type"]){
            if($debug_profile_matcher == "yes"){
                $json["data"][] = "Filtering $profile_name: no RAID controller.";
//                print("Filtering $profile_name: no RAID controller.\n");
            }
            continue;
        }
        $new_profiles[$profile_name] = $profiles[$profile_name];
    }
    $profiles = $new_profiles;

    # Filter on existing block devices and HDD layout
    $new_profiles = Array();
    $profile_names = array_keys($profiles);
    foreach($profile_names as &$profile_name){
        $profile_hdd_layouts = $profiles[$profile_name]["hdd"]["layout"];
        $machine_temp_hdds = $machine["hdds"];
        $machine_match = "yes";
        if($machine["controller_type"] == "megacli"){
            $layout_nums = array_keys($profile_hdd_layouts);
            foreach($layout_nums as &$layout_num){
                $layout = $profile_hdd_layouts[$layout_num];
                $search_how_many_drives = $layout["num_min"];
                $search_hdd_min_size = $layout["size_min"];
                $search_hdd_max_size = $layout["size_max"];
                $layout_match = "yes";
                for($i=0;$i<$search_how_many_drives;$i++){
                    $machine_hdd_ids = array_keys($machine_temp_hdds);
                    $hdd_match = "no";
                    foreach($machine_hdd_ids as &$machine_hdd_id){
                        $hdd_size_gb = floor($machine_temp_hdds[$machine_hdd_id]["size"] / (1024 * 1024 * 1024));
                        if($hdd_size_gb >= $search_hdd_min_size && $hdd_size_gb <= $search_hdd_max_size){
                            $hdd_match = "yes";
                            unset($machine_temp_hdds[$machine_hdd_id]);
                            break;
                        }
                    }
                    if($hdd_match == "no"){
                        $layout_match = "no";
                    }
                }
                if($layout_match == "no"){
                    if($debug_profile_matcher == "yes"){
                        $json["data"][] = "Filtering $profile_name: RAID drives does not match.";
//                        print("Filtering $profile_name: RAID drives does not match.\n");
                    }
                    $machine_match = "no";
                    break;
                }
            }
            if(isset($profiles[$profile_name]["hdd"]["hdd-num-exact-match"]) && $profiles[$profile_name]["hdd"]["hdd-num-exact-match"] == "yes"){
                $size_temp_hdds = sizeof($machine_temp_hdds);
//                echo "Profile $profile_name has hdd-num-exact-match, num HDD is $size_temp_hdds\n";
                if( sizeof($machine_temp_hdds) != 0){
                    if($debug_profile_matcher == "yes"){
                        $json["data"][] = "Filtering $profile_name: RAID drives does not match and hdd-num-exact-match is yes.";
//                        print("Filtering $profile_name: RAID drives does not match and hdd-num-exact-match is yes.\n");
                    }
                    $machine_match = "no";
                }
//                $sizeofarray = sizeof($machine_temp_hdds);
//                print_r($machine_temp_hdds);
//                $layout_match = "no";
            }
        }else{
            echo "";
        }
        if($machine_match == "yes"){
            $new_profiles[$profile_name] = $profiles[$profile_name];
        }
    }
    $profiles = $new_profiles;

    $profile_names = array_keys($profiles);
    foreach ($profile_names as &$profile_name){
        $json["data"][] = $profile_name;
    }
    return $json;
}

function hardware_profile_check_megacli_applied($con, $conf, $machine_id, $profile_name){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    if($profile_name == ""){
        $ret = hardware_profile_guess_profile($con, $conf, $machine_id);
        if($ret["status"] != "success"){
            return $ret;
        }
        if(sizeof($ret["data"]) != 1){
            $json["status"] = "error";
            $json["message"] = "No profile name as parameter, and could not guess hardware profile.";
            return $json;
        }
        $profile_name = $ret["data"][0];
    }

    $ret = hardware_profile_load_profile($con, $conf, $profile_name);
    if($ret["status"] != "success"){
        return $ret;
    }
    $profile = $ret["data"];


    $ret = hardware_profile_load_machine($con, $conf, $machine_id);
    if($ret["status"] != "success"){
        return $ret;
    }
    $machine = $ret["data"];

    $hdd_layout = $profile["hdd"]["layout"];
    $hdd_layout_ids = array_keys($hdd_layout);
    $machine_bd_temp = $machine["bd"];
    foreach($hdd_layout_ids as $hdd_layout_id){
        switch($hdd_layout_id){
        case "0":
            $devname = "sda";
            break;
        case "1":
            $devname = "sdb";
            break;
        case "2":
            $devname = "sdc";
            break;
        case "3":
            $devname = "sdd";
            break;
        case "4":
            $devname = "sde";
            break;
        case "5":
            $devname = "sdf";
            break;
        case "6":
            $devname = "sdg";
            break;
        case "7":
            $devname = "sdg";
            break;
        case "8":
            $devname = "sdh";
            break;
        case "9":
            $devname = "sdi";
            break;
        case "10":
            $devname = "sdj";
            break;
        case "11":
            $devname = "sdk";
            break;
        }
        $size_min = $hdd_layout[$hdd_layout_id]["size_min"];
        $size_max = $hdd_layout[$hdd_layout_id]["size_max"];

        $has_hdd_match = "no";
        foreach($machine_bd_temp as &$machine_bd){
            if($machine_bd["name"] == $devname){
                $machine_hdd_size_gb = floor($machine_bd["size_mb"] / 1024);
                if($size_min <= $machine_hdd_size_gb && $size_max >= $machine_hdd_size_gb){
                    $has_hdd_match = "yes";
                }
            }
        }
        if($has_hdd_match == "no"){
            $json["data"] = "no";
            return $json;
        }
    }

    if(isset($profile["hdd"]["hdd-num-exact-match"]) && $profile["hdd"]["hdd-num-exact-match"] == "yes"){
        if(sizeof($profile["hdd"]["layout"]) != sizeof($machine["bd"])){
            $json["data"] = "no";
            return $json;
        }
    }

    $json["data"] = "yes";
    return $json;
}

function hardware_profile_list($con, $conf){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    $json_file = file_get_contents("/etc/openstack-cluster-installer/hardware-profiles.json");
    if($json_file === FALSE){
        $json["status"] = "error";
        $json["message"] = "Cannot load /etc/openstack-cluster-installer/hardware-profiles.json.";
        return $json;
    }
    $profiles = json_decode($json_file, TRUE);
    if($profiles === FALSE || $profiles === NULL){
        $json["status"] = "error";
        $json["message"] = "Cannot decode /etc/openstack-cluster-installer/hardware-profiles.json.";
        return $json;
    }
    $json["data"] = $profiles;

    return $json;
}

function hardware_profile_remove_hdd_in_slot($physdrives, $hdd){
    $hdd_indexes = array_keys($physdrives);
    foreach($hdd_indexes as &$hdd_index){
        $one_hdd = $physdrives[$hdd_index];
        if($one_hdd["slot"] == $hdd["slot"] && $one_hdd["controller"] == $hdd["controller"] && $one_hdd["enclosure"] == $hdd["enclosure"]){
//            print("Found hdd to remove in index $hdd_index\n");
            unset($physdrives[$hdd_index]);
            return $physdrives;
        }
    }
    return $physdrives;
}

function search_raid_cli($con, $conf, $machine){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    $cmd = "which storcli64";
    $exe_path = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    if($exe_path == "/usr/bin/storcli64"){
        $cmd = "storcli64 /call/eall/sall show | grep 'No Controller found'";
        $no_ctrl = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        if($no_ctrl != 'Description = No Controller found'){
            return "storcli64";
        }
    }

    $cmd = "which storcli_x64";
    $exe_path = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    if($exe_path == "/usr/bin/storcli_x64"){
        $cmd = "storcli_x64 /call/eall/sall show | grep 'No Controller found'";
        $no_ctrl = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        if($no_ctrl != 'Description = No Controller found'){
            return "storcli_x64";
        }
    }

    $cmd = "which storcli";
    $exe_path = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    if($exe_path == "/usr/bin/storcli"){
        $cmd = "storcli /call/eall/sall show | grep 'No Controller found'";
        $no_ctrl = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        if($no_ctrl != 'Description = No Controller found'){
            return "storcli";
        }
    }

    $cmd = "which megacli";
    $exe_path = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);

    if($exe_path == "/usr/sbin/megacli"){
        return "megacli";
    }
    return FALSE;
}

function hardware_profile_apply_megacli_raid($con, $conf, $machine_id, $profile_name, $debug="no"){
    if($debug == "yes"){
        $debug_megacli_apply = "yes";
    }else{
        $debug_megacli_apply = "no";
    }
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    if($profile_name == ""){
        $ret = hardware_profile_guess_profile($con, $conf, $machine_id);
        if($ret["status"] != "success"){
            return $ret;
        }
        if(sizeof($ret["data"]) != 1){
            $json["status"] = "error";
            $json["message"] = "No profile name as parameter, and could not guess hardware profile.";
            return $json;
        }
        $profile_name = $ret["data"][0];
    }

    $ret = hardware_profile_load_profile($con, $conf, $profile_name);
    if($ret["status"] != "success"){
        return $ret;
    }
    $profile = $ret["data"];

    $ret = hardware_profile_load_machine($con, $conf, $machine_id);
    if($ret["status"] != "success"){
        return $ret;
    }
    $machine = $ret["data"];

    # Perform the ocicli commands as per "machine-set" field
    if(isset($profile["machine-set"])){
        foreach($profile["machine-set"] as &$machine_set) {
            # Replace %%COMPUTE_AGGREGATE%% by its value in auto-racking.json depending
            # on which switch the machine is connected to. This helps for example setting-up
            # a physical network that depends on the switch name, for example if we're doing
            # routed networks.
            $ret = auto_racking_guess_location($con, $conf, $machine_id);
            if($ret["status"] == "success" && sizeof($ret["data"]) >= 0){
                $switch_hostname = $ret["data"]["switch_hostname"];
                $ret = load_racking_info_config($con, $conf);
                if($ret["status"] == "success"){
                    $racking_info = $ret["data"];
                    if( isset($racking_info["switchhostnames"][ $switch_hostname ]["compute-aggregate"]) ){
                        $compute_aggregate = $racking_info["switchhostnames"][ $switch_hostname ]["compute-aggregate"];
                        $machine_set = str_replace("%%COMPUTE_AGGREGATE%%", $compute_aggregate, $machine_set);
                    }
                }
            }

            $cmd = "OCI_API_URL='http://localhost/oci/api.php?' ocicli machine-set " . $machine["serial"] . " $machine_set";
            $output = array();
            $return_var = 0;
            exec($cmd, $output, $return_var);
        }
    }

    $cli_path = search_raid_cli($con, $conf, $machine);
    if($cli_path == FALSE){
        $json["status"] = "error";
        $json["message"] = "Cannot find storcli/megacli.";
        return $json;
    }

    # Get the enclosure number
    if($cli_path == "megacli"){
        $cmd = "megacli -EncInfo -aALL -NoLog | grep 'Device ID' | cut -d: -f2 | cut -d' ' -f2";
    }else{
        $cmd = "$cli_path /call show | grep -A6 'Enclosure LIST' | tail -n1 | cut -d' ' -f1";
    }
    $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    $enclosure_number = $ret;

    $ret = hardware_profile_check_megacli_applied($con, $conf, $machine_id, $profile_name);
    if($ret["status"] != "success"){
        return $ret;
    }
    if($ret["data"] == "yes" && $debug_megacli_apply == "no"){
        $json["data"] = "Already applied.";
        return $json;
    }

    # Clear all foreign RAID
    if($cli_path == "megacli"){
        $cmd = "megacli -CfgForeign -Clear -a0";
    }else{
        $cmd = "$cli_path /c0/eall/sall delete jbod";
    }
    if($debug_megacli_apply == "yes"){
        $json["data"][] = $cmd;
    }else{
        $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    }

    # Delete any existing virtual disk
    if($cli_path == "megacli"){
        $cmd = "megacli -CfgLdDel -LALL -a0";
    }else{
        $cmd = "$cli_path /call /vall del";
    }
    if($debug_megacli_apply == "yes"){
        $json["data"][] = $cmd;
    }else{
        $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    }

    # Make all HDD as "Unconfigured, Good"
    foreach($machine["physbd"] as &$hdd){
        $controller = $hdd["controller"];
        $enclosure = $hdd["enclosure"];
        $slot = $hdd["slot"];
        if($cli_path == "megacli"){
            $cmd = "megacli -PDMakeGood -PhysDrv[$enclosure_number:$slot] -force -a0";
        }else{
            $cmd = "$cli_path /c$controller/e$enclosure/s$slot set good";
        }
        if($debug_megacli_apply == "yes"){
            $json["data"][] = $cmd;
        }else{
            $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }
    }
    $layouts = $profile["hdd"]["layout"];

    $machine_physbd_tmp = $machine["physbd"];

    foreach($layouts as &$layout){
        $hdd_slots = Array();
        # Search for the HDDs that could matches the size we need
        $hdd_indexes = array_keys($machine_physbd_tmp);
        foreach($hdd_indexes as &$hdd_index){
            $one_hdd = $machine_physbd_tmp[$hdd_index];
            $hdd_size_gb = floor($one_hdd["size"] / (1024 * 1024 * 1024));
            $hdd_slot = $one_hdd;
            if($hdd_size_gb >= $layout["size_min"] && $hdd_size_gb <= $layout["size_max"]){
//                echo "Hdd in slot " . $one_hdd["slot"] . " matches.\n";
                $hdd_slots[] = $one_hdd;
//                unset($machine_physbd_tmp[$hdd_index]);
            }
        }
//        print_r($layout);
        $raid_type = $layout["raid-type"];
        if(isset($layout["raid-type"])){
            $options = $layout["options"];
        }else{
            $options = "";
        }
//        print_r($machine_physbd_tmp);
        switch($raid_type){
        case "JBOD":
            $raid_megacli_cfg_opt = "";
            if($cli_path == "megacli"){
                $megacli_cfg = "megacli -PDMakeJBOD -PhysDrv [";
            }else{
                $megacli_cfg = "";
            }
            $cnt = 0;
            foreach($hdd_slots as &$one_slot){
                if($cnt != 0){
                    if($cli_path == "megacli"){
                        $megacli_cfg .= ",";
                    }
                }
                $my_controller = $one_slot["controller"];
                $my_enclosure = $one_slot["enclosure"];
                $my_slot = $one_slot["slot"];
                if($cli_path == "megacli"){
                    $megacli_cfg .= "$my_enclosure:$my_slot";
                }else{
                    $megacli_cfg .= "$cli_path /c$my_controller/e$my_enclosure/s$my_slot set jbod";
                }
                $machine_physbd_tmp = hardware_profile_remove_hdd_in_slot($machine_physbd_tmp, $one_slot);
                $cnt+=1;
                if($cnt >= $layout["num_max"]){
                    break;
                }
            }
            if($cli_path == "megacli"){
                $megacli_cfg .= "] -a0";
            }
            break;
        case "0":
            $cnt = 0;
            $raid_megacli_cfg_opt = "";
            foreach($hdd_slots as &$one_slot){
                if($cnt != 0){
                    if($cli_path == "megacli"){
                        $raid_megacli_cfg_opt .= ",";
                    }else{
                        $raid_megacli_cfg_opt .= "-";
                    }
                }
                $my_controller = $one_slot["controller"];
                $my_enclosure = $one_slot["enclosure"];
                $my_slot = $one_slot["slot"];
                if($cli_path == "megacli"){
                    $raid_megacli_cfg_opt .= "$my_enclosure:$my_slot";
                }else{
                    $raid_megacli_cfg_opt .= "$my_slot";
                }
//                print("Removing slot $one_slot\n");
                $machine_physbd_tmp = hardware_profile_remove_hdd_in_slot($machine_physbd_tmp, $one_slot);
                $cnt+=1;
                if($cnt >= $layout["num_max"]){
                    break;
                }
            }
            if($cli_path == "megacli"){
                $megacli_cfg = "megacli -CfgLdAdd -r0 [";
            }else{
                $megacli_cfg = "$cli_path /call add vd type=r0 drives=$my_enclosure:$raid_megacli_cfg_opt";
            }
            if($cli_path == "megacli"){
                $megacli_cfg .= "] $options -a0";
            }
            break;
        case "1":
            $cnt = 0;
            $raid_megacli_cfg_opt = "";
            foreach($hdd_slots as &$one_slot){
                if($cnt != 0){
                    if($cli_path == "megacli"){
                        $raid_megacli_cfg_opt .= ",";
                    }else{
                        $raid_megacli_cfg_opt .= "-";
                    }
                }
                $my_controller = $one_slot["controller"];
                $my_enclosure = $one_slot["enclosure"];
                $my_slot = $one_slot["slot"];
                if($cli_path == "megacli"){
                    $raid_megacli_cfg_opt .= "$my_enclosure:$my_slot";
                }else{
                    $raid_megacli_cfg_opt .= "$my_slot";
                }
                $machine_physbd_tmp = hardware_profile_remove_hdd_in_slot($machine_physbd_tmp, $one_slot);
                $cnt+=1;
                if($cnt >= $layout["num_max"]){
                    break;
                }
            }
            if($cli_path == "megacli"){
                $megacli_cfg = "megacli -CfgLdAdd -r1 [";
            }else{
                $megacli_cfg = "$cli_path /call add vd type=r1 drives=$my_enclosure:$raid_megacli_cfg_opt";
            }
            if($cli_path == "megacli"){
                $megacli_cfg .= "] $options -a0";
            }
            break;
        case "10":
            $megacli_cfg = "megacli -CfgSpanAdd -r10 ";
            $flip = 0;
            $cnt = 0;
            foreach($hdd_slots as &$one_slot){
                if($flip == 0){
                    $flip = 1;
                    $megacli_cfg .= "-Array" . $cnt . "[$enclosure_number:" . $one_slot . ",";
                    $machine_physbd_tmp = hardware_profile_remove_hdd_in_slot($machine_physbd_tmp, $one_slot);
                }else{
                    $flip = 0;
                    $cnt += 1;
                    $megacli_cfg .= "$enclosure_number:" . $one_slot . "] ";
                    $machine_physbd_tmp = hardware_profile_remove_hdd_in_slot($machine_physbd_tmp, $one_slot);
                }
            }
            $megacli_cfg .= "$options -a0";
            break;
        default:
            $json["status"] = "error";
            $json["message"] = "Not recognized RAID type.";
            return $json;
            break;
        }
        if($debug_megacli_apply == "yes"){
            $json["data"][] = $megacli_cfg;
        }else{
            $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $megacli_cfg);
        }
    }

    if($debug_megacli_apply == "no"){
        $json["data"]="Applied";
    }
    return $json;
}

function hardware_profile_apply_megacli_reset_raid($con, $conf, $machine_id){
    $debug_megacli_apply = "no";
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    $ret = hardware_profile_load_machine($con, $conf, $machine_id);
    if($ret["status"] != "success"){
        return $ret;
    }
    $machine = $ret["data"];

    $cli_path = search_raid_cli($con, $conf, $machine);
    if($cli_path == FALSE){
        $json["status"] = "error";
        $json["message"] = "Cannot find storcli/megacli.";
        return $json;
    }

    # Clear all foreign RAID
    if($cli_path == "megacli"){
        $cmd = "megacli -CfgForeign -Clear -a0";
    }else{
        $cmd = "$cli_path /c0/eall/sall delete jbod";
    }
    if($debug_megacli_apply == "yes"){
        print($cmd."\n");
    }else{
        $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    }

    # Delete any existing virtual disk
    if($cli_path == "megacli"){
        $cmd = "megacli -CfgLdDel -LALL -a0";
    }else{
        $cmd = "$cli_path /call /vall del";
    }
    if($debug_megacli_apply == "yes"){
        print($cmd."\n");
    }else{
        $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    }

    # Do a CfgClr
    if($cli_path == "megacli"){
        $cmd = "megacli -CfgClr -Force -aALL";
        if($debug_megacli_apply == "yes"){
            print($cmd."\n");
        }else{
            $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }
    }

    # Get the enclosure number
    if($cli_path == "megacli"){
        $cmd = "megacli -EncInfo -aALL -NoLog | grep 'Device ID' | cut -d: -f2 | cut -d' ' -f2";
    }else{
        $cmd = "$cli_path /call show | grep -A6 'Enclosure LIST' | tail -n1 | cut -d ' ' -f1";
    }
    $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
    $enclosure_number = $ret;

    # Make all HDD as "Unconfigured, Good"
    foreach($machine["physbd"] as &$hdd){
        $slot = $hdd["slot"];
        if($cli_path == "megacli"){
            $cmd = "megacli -PDMakeGood -PhysDrv[$enclosure_number:$slot] -force -a0";
        }else{
            $cmd = "$cli_path /call/eall/s$slot set good";
        }
        if($debug_megacli_apply == "yes"){
            print($cmd."\n");
        }else{
            $ret = send_ssh_cmd($conf, $con, $machine["ipaddr"], $cmd);
        }
    }
    return $json;
}

function hardware_profile_after_puppet_controller_commands($con, $conf, $machine_id){
    $json["status"] = "success";
    $json["message"] = "Successfuly queried API.";

    // Load the machine
    $ret = hardware_profile_load_machine($con, $conf, $machine_id);
    if($ret["status"] != "success"){
        return $ret;
    }
    $machine = $ret["data"];

    // Find the 1st controller of the cluster
    $q = "SELECT first_master_machine_id FROM clusters WHERE id='".$machine["cluster"]."'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $n = mysqli_num_rows($r);
    if($n != 1){
        $json["status"] = "error";
        $json["message"] = "Cannot find 1st controller of cluster.";
        return $json;
    }
    $cluster = mysqli_fetch_array($r);
    $first_master_machine_id = $cluster["first_master_machine_id"];

    // Find the IP address of the 1st controller
    $q = "SELECT ipaddr FROM machines WHERE id='$first_master_machine_id'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $n = mysqli_num_rows($r);
    if($n != 1){
        $json["status"] = "error";
        $json["message"] = "Cannot find IP address of 1st controller of cluster.";
        return $json;
    }
    $first_master_machine = mysqli_fetch_array($r);
    $first_master_machine_ipaddr = $first_master_machine["ipaddr"];

    // Get its hardware profile
    $ret = hardware_profile_guess_profile($con, $conf, $machine_id);
    if($ret["status"] != "success"){
        return $ret;
    }
    if(sizeof($ret["data"]) != 1){
        $json["status"] = "error";
        $json["message"] = "Could not guess hardware profile.";
        return $json;
    }
    $profile_name = $ret["data"][0];

    $ret = hardware_profile_load_profile($con, $conf, $profile_name);
    if($ret["status"] != "success"){
        return $ret;
    }
    $profile = $ret["data"];

    if(isset($profile["after-puppet-controller-command"])){
        foreach($profile["after-puppet-controller-command"] as &$cmd) {
            // Replace the hostname and aggregate from the template.
            $hostname_replaced = str_replace("%%HOSTNAME%%", $machine["hostname"], $cmd);

            // Replace the compute-aggregate depending on what's in auto-racking.json
            $ret = auto_racking_guess_location($con, $conf, $machine_id);
            if($ret["status"] != "success"){
                $aggregate_replaced = $hostname_replaced;
            }else{
                if(sizeof($ret["data"]) == 0){
                    $json["status"] = "error";
                    $json["message"] = "Cannot guess racking location.";
                    return $json;
                }
                $switch_hostname = $ret["data"]["switch_hostname"];

                $ret = load_racking_info_config($con, $conf);
                if($ret["status"] != "success"){
                    $aggregate_replaced = $hostname_replaced;
                }else{
                    $racking_info = $ret["data"];
                    if( !isset($racking_info["switchhostnames"][ $switch_hostname ]["compute-aggregate"]) ){
                        $aggregate_replaced = $hostname_replaced;
                    }else{
                        $compute_aggregate = $racking_info["switchhostnames"][ $switch_hostname ]["compute-aggregate"];
                        $aggregate_replaced = str_replace("%%COMPUTE_AGGREGATE%%", $compute_aggregate, $hostname_replaced);
                    }
                }
            }

            $after_puppet_cmd = ". /root/oci-openrc ; $aggregate_replaced";

            send_ssh_cmd($conf, $con, $first_master_machine_ipaddr, $after_puppet_cmd);
//            echo $after_puppet_cmd."\n";
        }
    }
}

?>