<?php

require_once("inc/read_conf.php");
require_once("inc/db.php");
require_once("inc/ssh.php");
require_once("inc/idna_convert.class.php");
require_once("inc/validate_param.php");
require_once("inc/slave_actions.php");
require_once("inc/auth.php");
require_once("inc/ipmi_cmds.php");
require_once("inc/hardware_profile.php");
require_once("inc/auto_racking.php");
require_once("inc/plugin_dns.php");
require_once("inc/plugin_monitoring.php");
require_once("inc/plugin_root_pass.php");
require_once("inc/plugin_ipmi_pass.php");
require_once("inc/auto_provision.php");

$conf = readmyconf();
$con = connectme($conf);

if(oci_ip_check($con, $conf) === FALSE){
    die("Source IP not in openstack-cluster-installer.conf.");
}

$remote_addr = $_SERVER['REMOTE_ADDR'];

$safe_chassis_serial = safe_serial("chassis-serial");
if($safe_chassis_serial === FALSE){
    $q = "SELECT * FROM machines WHERE dhcp_ip='$remote_addr'";
}else{
    $q = "SELECT * FROM machines WHERE serial='$safe_chassis_serial'";
}

$status = "";
$puppet_status = "";
$update_initial_cluster_setup_var = "no";

$r = mysqli_query($con, $q);
$n = mysqli_num_rows($r);
if($n == 0){
    die();
}else{
    $machine = mysqli_fetch_array($r);

    $id = $machine["id"];
    if( isset($_REQUEST["status"]) ){
        switch($_REQUEST["status"]){
        case "live":
            $status = ", status='live'";
            break;
        case "installing":
            $status = ", status='installing'";
            break;
        case "installed":
            $status = ", status='installed'";
            // Since there can be a host in the between doing SNAT, the REMOTE_ADDR
            // can be wrong, so we fix that by reading the parameter.
            $safe_ipv4 = safe_ipv4("ipaddr");
            if($safe_ipv4 === FALSE){
                error_log("install-status.php: No ipaddr reported after install!");
            }else{
                $remote_addr = $safe_ipv4;
                // As the machine has just booted, we must update its IP,
                // otherwise subsequent calls (ie: machine_gen_root_pass)
                // may fail.
                $machine["ipaddr"] = $safe_ipv4;
                if($safe_chassis_serial === FALSE){
                    die("Machine reports installed, but safe_chassis_serial is FALSE: impossible case, so dying...");
                }
                $q = "UPDATE machines SET ipaddr='$safe_ipv4' WHERE serial='$safe_chassis_serial'";
                $r = mysqli_query($con, $q);
            }
            // Since the machine is booted and installed, we need to sign the puppet cert.
            // We can do it with sudo, as there's a sudoers file installed.
            $cmd = "ls /usr/bin/puppetserver";
            $output = array();
            $return_var = 0;
            exec($cmd, $output, $return_var);
            if($return_var == 0){
                $puppet_master_is_7_or_more = "yes";
            }else{
                $puppet_master_is_7_or_more = "no";
            }

            $output = "";
            $machine_hostname = $machine["hostname"];
            if($puppet_master_is_7_or_more == "yes"){
                $mycmd = "puppetserver ca sign --certname";
            }else{
                $mycmd = "puppet cert sign";
            }
            error_log("install-status.php: sudo /usr/bin/$mycmd $machine_hostname");
            $cmd = "sudo /usr/bin/$mycmd " . $machine_hostname;
            exec($cmd , $output);

            // As the machine is installed, we can setup its root password.
            machine_gen_root_pass($con, $conf, $machine);
            machine_save_ipmi_pass($con, $conf, $machine);

            break;
        case "firstboot":
            ipmi_set_boot_device($con, $conf, $id, "disk");
            $status = ", status='firstboot'";
            break;
        case "puppet-running":
            $puppet_status = ", puppet_status='running'";
            break;
        case "puppet-success":
            $puppet_status = ", puppet_status='success'";
            $update_initial_cluster_setup_var = "yes";

            // If puppet is successful, setup the monitoring.
            machine_add_to_monitoring($con, $conf, $machine);

            break;
        case "puppet-failure":
            $puppet_status = ", puppet_status='failure'";
            break;
        default:
            $status = ", status='unkown'";
            break;
        }
    }else{
        $status = ", status='unkown'";
    }
    // We keep the machine id...
    if($safe_chassis_serial === FALSE){
        $req = "UPDATE machines SET lastseen=NOW() $puppet_status $status WHERE ipaddr='$remote_addr'";
    }else{
        if($_REQUEST["status"] == "live"){
            $req = "UPDATE machines SET lastseen=NOW() $puppet_status $status, ipaddr='$remote_addr', dhcp_ip='$remote_addr' WHERE serial='$safe_chassis_serial'";
        }else{
            $req = "UPDATE machines SET lastseen=NOW() $puppet_status $status, ipaddr='$remote_addr' WHERE serial='$safe_chassis_serial'";
        }
    }
    $r = mysqli_query($con, $req);
    if($update_initial_cluster_setup_var == "yes" && $safe_chassis_serial !== FALSE){
        $q = "SELECT cluster,role,id FROM machines WHERE serial='$safe_chassis_serial'";
        $r = mysqli_query($con, $q);
        if($r !== FALSE){
            $n = mysqli_num_rows($r);
            if($n == 1){
                $machine = mysqli_fetch_array($r);
                $machine_id = $machine["id"];
                $clusterid = $machine["cluster"];

                // Get the number of cephosd nodes
                $q = "SELECT * FROM machines WHERE (cluster='$clusterid' AND role='cephosd') OR (cluster='$clusterid' AND role='compute' AND compute_is_cephosd='yes')";
                $r = mysqli_query($con, $q);
                if($r === FALSE){
                    $json["status"] = "error";
                    $json["message"] = mysqli_error($con)." line ".__LINE__." file ".__FILE__;
                    return $json;
                }
                $num_cephosd_nodes = mysqli_num_rows($r);

                // Get the number of cephmon nodes
                $q = "SELECT * FROM machines WHERE cluster='$clusterid' AND role='cephmon'";
                $r = mysqli_query($con, $q);
                if($r === FALSE){
                    $json["status"] = "error";
                    $json["message"] = mysqli_error($con)." line ".__LINE__." file ".__FILE__;
                    return $json;
                }
                $num_cephmon_nodes = mysqli_num_rows($r);

                // Get the cluster raw
                $q = "SELECT * FROM clusters WHERE id='$clusterid'";
                $r = mysqli_query($con, $q);
                if($r === FALSE){
                    $json["status"] = "error";
                    $json["message"] = mysqli_error($con)." line ".__LINE__." file ".__FILE__;
                    return $json;
                }
                $n = mysqli_num_rows($r);
                if($n != 1){
                    $json["status"] = "error";
                    $json["message"] = "Could not find cluster line ".__LINE__." file ".__FILE__;
                    return $json;
                }
                $cluster = mysqli_fetch_array($r);

                switch($machine["role"]){
                case "controller":
                    $q = "SELECT hostname FROM machines WHERE cluster='$clusterid' AND role='controller' AND puppet_status NOT LIKE 'success'";
                    $r = mysqli_query($con, $q);
                    if($r !== FALSE){
                        $n = mysqli_num_rows($r);
                        if($n == 0){
                            # If we're on the first stage success of hyper-converged (ie: cephmon on controllers)
                            # then we should start provisionning CephOSD on cephosd nodes or compute with cephosd.
                            if($num_cephosd_nodes > 0 && $num_cephmon_nodes == 0 && $cluster["initial_mon_on_ctrl"] == "yes"){
                                $q = "SELECT ipaddr FROM machines WHERE role='compute' AND compute_is_cephosd='yes' AND cluster='$clusterid'";
                                $r = mysqli_query($con, $q);
                                if($r !== FALSE){
                                    $n = mysqli_num_rows($r);
                                    for($i=0;$i<$n;$i++){
                                        $compute_machine = mysqli_fetch_array($r);
                                        $compute_machine_ip = $compute_machine["ipaddr"];
                                        # Restart the oci-first-boot, so that the compute hyperconverged machines
                                        # gets installed, this time with nova-compute, not just only with the cephosd role.
                                        $cmd = "touch /var/lib/oci-first-boot";
                                        send_ssh_cmd($conf, $con, $compute_machine_ip, $cmd);
                                        $cmd = "/usr/bin/oci-first-boot-wrapper 2>/dev/null 1>/dev/null";
                                        send_ssh_cmd($conf, $con, $compute_machine_ip, $cmd);
                                    }
                                }
                            # If not, it means we're finished with the controller setup, therefor, initial_cluster_setup
                            # can be setup to no.
                            }else{
                                $q = "UPDATE clusters SET initial_cluster_setup='no' WHERE id='$clusterid'";
                                $r = mysqli_query($con, $q);
                            }
                        }
                    }
                    break;
                case "compute":
                    # If we're on the case where there's no cephmon, only cephmon on the controllers (and
                    # probably also cephosd on computes), then once compute cephosd are setup, we need to
                    # get the controllers to finish installing everything.
                    if($num_cephosd_nodes > 0 && $num_cephmon_nodes == 0 && $cluster["initial_mon_on_ctrl"] == "yes"){
                        $q = "SELECT COUNT(id) AS num_not_installed FROM machines WHERE puppet_status!='success' AND cluster='$clusterid' AND (role='controller' OR (role='compute' AND compute_is_cephosd='yes'))";
                        $r = mysqli_query($con, $q);
                        if($r === FALSE){
                            $json["status"] = "error";
                            $json["message"] = mysqli_error($con)." line ".__LINE__." file ".__FILE__;
                            return $json;
                        }
                        $res = mysqli_fetch_array($r);
                        $n = $res["num_not_installed"];
                        if($n == 0){
                            $q = "UPDATE clusters SET initial_mon_on_ctrl='no' WHERE id='$clusterid'";
                            $r = mysqli_query($con, $q);
                            if($r === FALSE){
                                $json["status"] = "error";
                                $json["message"] = mysqli_error($con)." line ".__LINE__." file ".__FILE__;
                                return $json;
                            }

                            $q = "SELECT * FROM machines WHERE cluster='$clusterid' AND (role='compute' OR role='controller')";
                            $r = mysqli_query($con, $q);
                            if($r === FALSE){
                                $json["status"] = "error";
                                $json["message"] = mysqli_error($con)." line ".__LINE__." file ".__FILE__;
                                return $json;
                            }
                            $n = mysqli_num_rows($r);
                            for($j=0;$j<$n;$j++){
                                $a_machine = mysqli_fetch_array($r);
                                $a_machine_id = $a_machine["id"];
                                $machine_networks = slave_fetch_network_config($con, $conf, $a_machine_id);
                                if(sizeof($machine_networks["networks"]) == 0){
                                    $json["status"]  = "error";
                                    $json["message"] = "No network configured for this machine.";
                                    return $json;
                                }

                                // We just fetch the first network that's not public and vm-trafic for now, maybe we'll need to be
                                // more selective later, let's see...
                                for($i=0;$i<sizeof($machine_networks["networks"]);$i++){
                                    if($machine_networks["networks"][$i]["is_public"] == 'no' && $machine_networks["networks"][$i]["role"] != "vm-net" && $machine_networks["networks"][$i]["role"] != "ovs-bridge" && $machine_networks["networks"][$i]["role"] != "ceph-cluster" && $machine_networks["networks"][$i]["role"] != "ipmi" && $machine_networks["networks"][$i]["role"] != "vip"){
                                        $a_network_id = $machine_networks["networks"][$i]["id"];
                                        continue;
                                    }
                                }

                                // Get this machine's IP and hostname
                                $qm = "SELECT machines.hostname AS hostname, INET_NTOA(ips.ip) AS ipaddr FROM machines, ips WHERE machines.id='$a_machine_id' AND machines.cluster='$clusterid' AND machines.id=ips.machine  AND ips.network='$a_network_id'";
                                $rm = mysqli_query($con, $qm);
                                if($rm === FALSE){
                                    $json["status"] = "error";
                                    $json["message"] = mysqli_error($con)." line ".__LINE__." file ".__FILE__;
                                    return $json;
                                }
                                $nm = mysqli_num_rows($rm);
                                if($nm != 1){
                                    $json["status"] = "error";
                                    $json["message"] = "No such hostname in database when doing $qm.";
                                    return $json;
                                }
                                $a_machine_netconf = mysqli_fetch_array($rm);
                                $a_machine_hostname = $a_machine_netconf["hostname"];
                                $a_machine_ip = $a_machine_netconf["ipaddr"];

                                $command = "touch /var/lib/oci-first-boot";
                                send_ssh_cmd($conf, $con, $a_machine_ip, $command);
                                if($a_machine["role"] == "controller"){
                                    $command = "/usr/bin/oci-first-boot-wrapper 2>/dev/null 1>/dev/null";
                                    send_ssh_cmd($conf, $con, $a_machine_ip, $command);
                                }
                            }
                        }
                        break;
                    }
                    # Since this is a new compute, we must do a nova-manage cell_v2 discover_hosts so that the machine
                    # appears in the hypervisor list.
                    # However, if the compute is hyper-converged, we shall delay this until all controllers are installed,
                    # and the compute gets nova up.
                    $q = "SELECT * FROM clusters WHERE id='$clusterid'";
                    $r = mysqli_query($con, $q);
                    if($r !== FALSE){
                        $n = mysqli_num_rows($r);
                        if($n > 0){
                            $clusterid = $machine["cluster"];
                            $q = "SELECT ipaddr FROM machines WHERE cluster='$clusterid' AND role='controller' AND puppet_status LIKE 'success' LIMIT 1";
                            $r = mysqli_query($con, $q);
                            if($r !== FALSE){
                                $n = mysqli_num_rows($r);
                                if($n > 0){
                                    $controller = mysqli_fetch_array($r);
                                    $ip_addr = $controller["ipaddr"];
                                    $cmd = "su nova -s /bin/sh -c 'nova-manage cell_v2 discover_hosts'";
                                    send_ssh_cmd($conf, $con, $ip_addr, $cmd);
                                }
                            }
                        }
                    }
                    # Set the OSD setup var to no
                    $q = "UPDATE machines SET ceph_osd_initial_setup='no' WHERE id='$machine_id'";
                    $r = mysqli_query($con, $q);
                    break;
                case "billosd":
                case "cephosd":
                    # Set the OSD setup var to no
                    $q = "UPDATE machines SET ceph_osd_initial_setup='no' WHERE id='$machine_id'";
                    $r = mysqli_query($con, $q);
                    break;
                default:
                    break;
                }
                // Apply an eventual command on the controller if it's defined in the hardware-profile.json
                hardware_profile_after_puppet_controller_commands($con, $conf, $machine["id"]);
            }
        }
    }
}

?>
