<?php

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

    # Fetch cluster name and domain
    $q = "SELECT * FROM clusters WHERE id='$cluster_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 cluster in database.";
        return $json;
    }
    $a = mysqli_fetch_array($r);
    $cluster_name = $a["name"];
    $cluster_domain = $a["domain"];

    # Fetch role ID
    $q = "SELECT * FROM roles WHERE name='$role_name'";
    $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 == 0){
        $json["status"] = "error";
        $json["message"] = "Cannot find role in database.";
        return $json;
    }
    $a = mysqli_fetch_array($r);
    $role_id = $a["id"];

    # Get the role count for this role,
    # if the record doesn't exist, create it,
    # otherwise, increment, and finally, calculate
    # the current role count for the node we're adding.
    $q = "SELECT * FROM rolecounts WHERE cluster='$cluster_id' AND role='$role_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 == 0){
        $role_count = 0;
        $q = "INSERT INTO rolecounts (id, cluster, role, count) VALUES ('', '$cluster_id', '$role_id', '1')";
        $r = mysqli_query($con, $q);
        if($r === FALSE){
            $json["status"] = "error";
            $json["message"] = mysqli_error($con);
            return $json;
        }
        $safe_role_count_id = mysqli_insert_id($con);
        $safe_role_count = "1";
    }else{
        $a = mysqli_fetch_array($r);
        $safe_role_count = $a["count"] + 1;
        $safe_role_count_id = $a["id"];

        $q = "UPDATE rolecounts SET count='$safe_role_count' WHERE id='$safe_role_count_id'";
        $r = mysqli_query($con, $q);
        if($r === FALSE){
            $json["status"] = "error";
            $json["message"] = mysqli_error($con);
            return $json;
        }
    }

    # Check if there's no controller yet in the cluster.
    # If there's none, set this machine as the first_master
    if($role_name == "controller"){
        $q = "SELECT id FROM machines WHERE role='controller' AND cluster='$cluster_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 == 0){
            $q = "UPDATE clusters SET first_master_machine_id='$machine_id' WHERE id='$cluster_id'";
            $r = mysqli_query($con, $q);
            if($r === FALSE){
                $json["status"] = "error";
                $json["message"] = mysqli_error($con);
                return $json;
            }
        }
    }

    # Finally perform the UPDATE query for the machine so
    # that it joins the cluster
    $safe_hostname = $cluster_name . "-" . $role_name . "-" . $safe_role_count . "." . $cluster_domain;
    $q = "UPDATE machines SET cluster='$cluster_id', role='$role_name', hostname='$safe_hostname', location_id='$location_id' WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    # and assign IPs to it
    $json = slave_assign_all_networks_ip_addresses($con, $conf, $machine_id, "machine", $location_id);

    // Create the machine's SSL cert
    $cmd = "sudo /usr/bin/oci-gen-slave-node-cert $safe_hostname";
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    return $json;
}

function insert_cluster_pass($con, $conf, $cluster_id, $service, $passtype){
    $bytes = openssl_random_pseudo_bytes(32, $crypto_strong);
    $hex   = bin2hex($bytes);
    $q = "INSERT INTO passwords (id, cluster, service, passtype, pass) VALUES ('', '$cluster_id', '$service', '$passtype', '$hex')";
    $r = mysqli_query($con, $q);
}

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

    // Check if cluster exists
    $r = mysqli_query($con, "SELECT * FROM clusters WHERE name='$cluster_name'");
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $n = mysqli_num_rows($r);
    if($n != 0){
        $json["status"] = "error";
        $json["message"] = "Error: cluster name $cluster_name already exists.";
        return $json;
    }

    // Create the cluster
    $q = "INSERT INTO clusters (id, name, domain) VALUES ('', '$cluster_name', '$cluster_domain'); ";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }
    $cluster_id = mysqli_insert_id($con);

    // Provision passwords for later
    insert_cluster_pass($con, $conf, $cluster_id, 'keystone', 'adminuser');
    insert_cluster_pass($con, $conf, $cluster_id, 'keystone', 'db');
    insert_cluster_pass($con, $conf, $cluster_id, 'keystone', 'messaging');
    insert_cluster_pass($con, $conf, $cluster_id, 'keystone', 'credential1');
    insert_cluster_pass($con, $conf, $cluster_id, 'keystone', 'credential2');
    insert_cluster_pass($con, $conf, $cluster_id, 'keystone', 'fernetkey1');
    insert_cluster_pass($con, $conf, $cluster_id, 'keystone', 'fernetkey2');
    insert_cluster_pass($con, $conf, $cluster_id, 'glance',   'db');
    insert_cluster_pass($con, $conf, $cluster_id, 'glance',   'messaging');
    insert_cluster_pass($con, $conf, $cluster_id, 'glance',   'authtoken');
    insert_cluster_pass($con, $conf, $cluster_id, 'nova',     'db');
    insert_cluster_pass($con, $conf, $cluster_id, 'nova',     'messaging');
    insert_cluster_pass($con, $conf, $cluster_id, 'nova',     'authtoken');
    insert_cluster_pass($con, $conf, $cluster_id, 'cinder',   'db');
    insert_cluster_pass($con, $conf, $cluster_id, 'cinder',   'messaging');
    insert_cluster_pass($con, $conf, $cluster_id, 'cinder',   'authtoken');
    insert_cluster_pass($con, $conf, $cluster_id, 'neutron',  'db');
    insert_cluster_pass($con, $conf, $cluster_id, 'neutron',  'messaging');
    insert_cluster_pass($con, $conf, $cluster_id, 'neutron',  'authtoken');
    insert_cluster_pass($con, $conf, $cluster_id, 'heat',     'db');
    insert_cluster_pass($con, $conf, $cluster_id, 'heat',     'messaging');
    insert_cluster_pass($con, $conf, $cluster_id, 'heat',     'authtoken');
    insert_cluster_pass($con, $conf, $cluster_id, 'heat',     'keystone_domain');
    insert_cluster_pass($con, $conf, $cluster_id, 'swift',    'authtoken');
    insert_cluster_pass($con, $conf, $cluster_id, 'swift',    'hashpathsuffix');
    insert_cluster_pass($con, $conf, $cluster_id, 'swift',    'hashpathprefix');

    $dir = "/var/lib/oci/clusters/$cluster_name";
    mkdir($dir, 0700);

    // Provision an API SSL certificate
    $api_hostname = $cluster_name . "-api." . $cluster_domain;
    $cmd = "sudo /usr/bin/oci-gen-slave-node-cert $api_hostname";
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    ##########################################
    ### Create an ssh key for this cluster ###
    ##########################################
    $ssh_key_dir = "/var/lib/oci/clusters/$cluster_name/ssh";
    mkdir($ssh_key_dir, 0700);
    $cmd = "ssh-keygen -P '' -f $ssh_key_dir/id_rsa";
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    return $json;
}

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

    $q = "SELECT * FROM clusters WHERE name='$cluster_name'";
    $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"] = "Error: cluster name doesn't exist.";
        return $json;
    }
    $cluster = mysqli_fetch_array($r);
    $cluster_id = $cluster["id"];

    $q = "DELETE FROM passwords WHERE cluster='$cluster_id'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }

    $q = "DELETE FROM clusters WHERE name='$cluster_name'";
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $json["status"] = "error";
        $json["message"] = mysqli_error($con);
        return $json;
    }

    return $json;
}

function slave_fetch_networks($con, $conf, $machine_id){
    $out = array(
        "status"   => "success",
        "message"  => "Succesfully fetched networks.",
        "networks" => array(),
    );
    // Fetch the machine
    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out["status"]  = "error";
        $out["message"] = "Cannot find machine: $machine_id.";
        return $out;
    }
    $machine = mysqli_fetch_array($r);
    $cluster_id = $machine["cluster"];
    $role = $machine["role"];
    $location_id = $machine["location_id"];

    // Fetch its network
    $q = "SELECT * FROM networks WHERE cluster='$cluster_id' AND role='$role' AND location_id='$location_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n >= 1){
        for($i=0;$i<$n;$i++){
            $out["networks"][] = mysqli_fetch_array($r);
        }
    }else{
        $q = "SELECT * FROM networks WHERE cluster='$cluster_id' AND role='norole' AND location_id='$location_id'";
        $r = mysqli_query($con, $q);
        $n = mysqli_num_rows($r);
        for($i=0;$i<$n;$i++){
            $out["networks"][] = mysqli_fetch_array($r);
        }
    }

    $q = "SELECT * FROM networks WHERE cluster='$cluster_id' AND role='all' AND location_id='$location_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    for($i=0;$i<$n;$i++){
        $out["networks"][] = mysqli_fetch_array($r);
    }
    return $out;
}

// Reserve an IP address in the "ips" table.
// usefor can be either machine or vip, if vip, then machine_id must be zero.
function reserve_ip_address($con, $conf, $network_id, $machine_id, $usefor){
    $out = array(
        "status"  => "success",
        "message" => "Succesfully reserved IP adresses.",
    );

    $q = "SELECT * FROM networks WHERE id='$network_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out["status"]  = "error";
        $out["message"] = "Cannot find network: $network_id.";
        return $out;
    }
    $network = mysqli_fetch_array($r);
    $network_ip   = $network["ip"];
    $network_name = $network["name"];
    $network_cidr = $network["cidr"];

    // Calculate first and last IP of the network
    $number_of_ip = 2 ** (32 - $network_cidr);
    $network_ip_long = ip2long($network_ip);
    $network_first_ip_long = $network_ip_long + 2;
    $netowrk_last_ip_long = $network_ip_long + $number_of_ip - 2;

    // ******** START SEMAPHORE ********
    $key   = ftok(__FILE__,'m');
    $mysem = sem_get($key);
    sem_acquire($mysem);

    // Check if there's either no IP left, or no IP provisionned yet.
    $q = "SELECT id FROM ips WHERE network='$network_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n >= ($number_of_ip - 3)){
        $out["status"]  = "error";
        $out["message"] = "No IP available in the network $network_name.";
        sem_release($mysem);
        return $out;
    }
    if($n == 0){
        // Just use the first IP
        $q = "INSERT INTO ips (usefor,network,type,ip,machine) VALUES ('$usefor', '$network_id', '4', '$network_first_ip_long','$machine_id')";
    }else{
        // Get first IP address available
        $q = "INSERT INTO ips (usefor,network,machine,type,ip) SELECT '$usefor', '$network_id', '$machine_id', '4', outip.ip+1 FROM ips outip WHERE network='$network_id' AND NOT (SELECT COUNT(*) FROM ips inip WHERE inip.ip = outip.ip+1 AND network='$network_id') ORDER BY ip ASC LIMIT 1";
    }
    $r = mysqli_query($con, $q);
    if($r === FALSE){
        $out["status"]  = "error";
        $out["message"] = "Could not reserve new IP, query: $q, error: ".mysqli_error($con);
        sem_release($mysem);
        return $out;
    }
    sem_release($mysem);
    // ******** END SEMAPHORE ********
    return $out;
}

function reserve_ip_to_all_slaves_of_network($con, $conf, $cluster_id, $network_id, $role){
    $out = array(
        "status" => "success",
        "message" => "Successfully assigned IP for network id $network_id and cluster $cluster_id.",
    );

    $q = "SELECT location_id FROM networks WHERE id='$network_id'";
    $r = mysqli_query($con, $q);
    $a = mysqli_fetch_array($r);
    $location_id = $a["location_id"];

    if($role != "all"){
        $q = "SELECT * FROM machines WHERE cluster='$cluster_id' AND role='$role' AND location_id='$location_id'";
    }else{
        $q = "SELECT * FROM machines WHERE cluster='$cluster_id' AND location_id='$location_id'";
    }
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    for($i=0;$i<$n;$i++){
        $machine = mysqli_fetch_array($r);
        $machine_id = $machine["id"];
        $ret = reserve_ip_address($con, $conf, $network_id, $machine_id, "machine");
        if($ret["status"] != "success"){
            return $ret;
        }
    }
    return $out;
}

function slave_assign_all_networks_ip_addresses($con, $conf, $id, $usefor, $location_id){
    $out = array(
        "status"  => "success",
        "message" => "Succesfully reserved IP adresses.",
    );
    if($usefor != "machine" && $usefor != "vip"){
        $out["status"]  = "error";
        $out["message"] = "Parameter usefor should be either machine or vip.";
    }

    if($usefor == "vip"){
        // If usefor is vip, then $id will in fact contain a network ID
        $network_id = $id;
    }else{
        $machine_id = $id;
    }

    // Fetch the machine
    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out["status"]  = "error";
        $out["message"] = "Cannot find machine: $machine_id.";
        return $out;
    }
    $machine = mysqli_fetch_array($r);
    $cluster_id = $machine["cluster"];
    $role = $machine["role"];

    $machine_networks = slave_fetch_networks($con, $conf, $machine_id);

    for($i=0;$i<sizeof($machine_networks["networks"]);$i++){
        $network_id   = $machine_networks["networks"][$i]["id"];
        if($machine_networks["networks"][$i]["is_public"] == "no"){
            $ret = reserve_ip_address($con, $conf, $network_id, $machine_id, "machine");
        }
        if($ret["status"] == "error"){
            return $ret;
        }
    }
    return $out;
}

function slave_fetch_network_config($con, $conf, $machine_id){
    $out = array(
        "status"  => "success",
        "message" => "Succesfully fetched network config.",
    );
    $machine_networks = slave_fetch_networks($con, $conf, $machine_id);
    for($i=0;$i<sizeof($machine_networks["networks"]);$i++){
        $q = "SELECT INET_NTOA(ip) AS ipaddr FROM ips WHERE network='". $machine_networks["networks"][$i]["id"] ."' AND machine='$machine_id'";
        $r = mysqli_query($con, $q);
        $n = mysqli_num_rows($r);
        if($n != 1){
            $out["status"]  = "error";
            $out["message"] = "Could not fetch IP for netowrk " . $machine_networks["networks"]["name"] . ".";
            return $out;
        }
        $a = mysqli_fetch_array($r);
        $machine_networks["networks"][$i]["ipaddr"] = $a["ipaddr"];
        $network_ip_long = ip2long($machine_networks["networks"][$i]["ip"]);
        $network_gateway_long = $network_ip_long + 1;
        $machine_networks["networks"][$i]["gateway"] = long2ip($network_gateway_long);
    }
    return $machine_networks;
}

function get_ethname_from_network_config($con, $conf, $machine_id, $iface_in){
        $iface = "";
        $qeth = "";
        switch($iface_in){
        case "eth0":
            $iface = "eth0";
            break;
        case "eth1":
            $iface = "eth1";
            break;
        case "eth2":
            $iface = "eth2";
            break;
        case "eth3":
            $iface = "eth3";
            break;
        case "eth4":
            $iface = "eth4";
            break;
        case "eth5":
            $iface = "eth5";
            break;
        case "10m1":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10' ORDER BY name LIMIT 1";
            break;
        case "10m2":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10' ORDER BY name LIMIT 1,1";
            break;
        case "10m3":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10' ORDER BY name LIMIT 2,1";
            break;
        case "10m4":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10' ORDER BY name LIMIT 3,1";
            break;
        case "100m1":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='100' ORDER BY name LIMIT 1";
            break;
        case "100m2":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='100' ORDER BY name LIMIT 1,1";
            break;
        case "100m3":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='100' ORDER BY name LIMIT 2,1";
            break;
        case "100m4":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='100' ORDER BY name LIMIT 3,1";
            break;
        case "1g1":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='1000' ORDER BY name LIMIT 1";
            break;
        case "1g2":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='1000' ORDER BY name LIMIT 1,1";
            break;
        case "1g3":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='1000' ORDER BY name LIMIT 2,1";
            break;
        case "1g4":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='1000' ORDER BY name LIMIT 3,1";
            break;
        case "10g1":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10000' ORDER BY name LIMIT 1";
            break;
        case "10g2":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10000' ORDER BY name LIMIT 1,1";
            break;
        case "10g3":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10000' ORDER BY name LIMIT 2,1";
            break;
        case "10g4":
            $qeth = "SELECT name FROM ifnames WHERE machine_id='$machine_id' AND max_speed='10000' ORDER BY name LIMIT 3,1";
            break;
        }
        if($qeth != ""){
            $reth = mysqli_query($con, $qeth);
            $neth = mysqli_num_rows($reth);
            if($neth != 1){
                $out["status"]  = "error";
                $out["message"] = "Cannot find block device: $q<br>";
                return $out;
            }
            $aeth = mysqli_fetch_array($reth);
            $iface = $aeth["name"];
        }
        return $iface;
}

function slave_install_server_os_command($con, $conf, $machine_id){
    $out = array(
        "status"  => "success",
        "message" => "Succesfully reserved IPs and generated command line.",
        "cmd"     => "",
    );
    // Fetch the machine
    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out["status"]  = "error";
        $out["message"] = "Cannot find machine: $machine_id.";
        return $out;
    }
    $machine = mysqli_fetch_array($r);
    $cluster_id = $machine["cluster"];
    $role = $machine["role"];

    // Get its block device
    $q = "SELECT * FROM blockdevices WHERE machine_id='$machine_id' AND name LIKE '%a'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out["status"]  = "error";
        $out["message"] = "Cannot find block device: $q<br>";
        return $out;
    }
    $a2 = mysqli_fetch_array($r);
    $install_hdd_name = $a2["name"];

    $machine_networks = slave_fetch_network_config($con, $conf, $machine_id);
    if(sizeof($machine_networks["networks"]) == 0){
        $out["status"]  = "error";
        $out["message"] = "No network configured for this machine.";
        return $out;
    }

    $network_params = "";
    for($i=0;$i<sizeof($machine_networks["networks"]);$i++){
        $onenet  = $machine_networks["networks"][$i];

        $netvlan = $onenet["vlan"];
        $addr_param = ",addr=" . $onenet["ipaddr"] . "/" . $onenet["cidr"] . ":" . $onenet["gateway"];

        $iface1 = get_ethname_from_network_config($con, $conf, $machine_id, $onenet["iface1"]);

        if($onenet["iface2"] != "none"){
            $iface2 = get_ethname_from_network_config($con, $conf, $machine_id, $onenet["iface2"]);
            if(is_null($netvlan)){
                $network_params .= " --static-iface type=bond,iface0=$iface1,iface1=$iface2" . $addr_param;
            }else{
                $network_params .= " --static-iface type=bondvlan,vlannum=$netvlan,iface0=$iface1,iface1=$iface2" . $addr_param;
            }
        }else{
            $network_params .= " --static-iface type=normal,iface0=$iface1" . $addr_param;
        }
        if($onenet["mtu"] != 0){
            $network_params .= ",mtu=" . $onenet["mtu"];
        }
    }

    // Get its cluster name and fetch the additional package list for this node
    $q = "SELECT * FROM clusters WHERE id='$cluster_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    $package_list_file = "";
    if($n == 1){
        $cluster = mysqli_fetch_array($r);
        $cluster_name = $cluster["name"];
        $package_list_path = "/var/lib/oci/clusters/$cluster_name/" . $machine["hostname"] . "/oci-packages-list";
        if(file_exists($package_list_path)){
            $package_list_file = ",";
            $package_list_file .= file_get_contents($package_list_path);
        }
    }

    $cmd  = "oci-install-with-report";
    $cmd .= $network_params;
    $cmd .= " --release ".$conf["releasenames"]["debian_release"];
    $cmd .= " --debootstrap-url ".$conf["network"]["debian_mirror"];
    $cmd .= " --sources.list-mirror ".$conf["network"]["debian_mirror"];
    $cmd .= " --security-mirror ".$conf["network"]["debian_security_mirror"];
    $cmd .= " --dest-hdd $install_hdd_name";
    $cmd .= " --no-cloud-init --extra-packages curl,less,joe,ssl-cert,most,screen,vim,vim-tiny,tcpd,xfsdump,unzip,tcpdump,ntpstat,ca-certificates,rpcbind,lftp,at,tree,lsof,bind9-host,dnsutils,strace,tmux,nano,bash-completion,openssl,ntp,file,net-tools,iproute2,ipmitool,ca-certificates,xfsprogs,parted,nmap,mtr-tiny,ladvd$package_list_file";
    $cmd .= " --hook-script /usr/bin/openstack-cluster-installer-bodi-hook-script";
    $cmd .= " --root-ssh-key /root/.ssh/authorized_keys";
    $cmd .= " --install-nonfree-repo --postinstall-packages firmware-bnx2,firmware-bnx2x,puppet";
    $cmd .= " --hostname " . $machine["hostname"];
    $cmd .= " --add-serial-getty ttyS1";
    $cmd .= " --reboot-after-install";
    if($role == "swiftstore"){
        $q = "SELECT * FROM blockdevices WHERE machine_id='$machine_id' AND name NOT LIKE '%a' ORDER BY name";
        $r = mysqli_query($con, $q);
        $n = mysqli_num_rows($r);
        if($n < 1){
            $out["status"]  = "error";
            $out["message"] = "Cannot find storage block device for this machine, and it's a swiftstore...<br>";
            return $out;
        }
        $format_cmd = " --xfsformat ";
        for($i=0;$i<$n;$i++){
            $blockdev = mysqli_fetch_array($r);
            if($i != 0){
                $format_cmd .= ",";
            }
            $format_cmd .= $blockdev["name"];
        }
        $cmd .= $format_cmd;
    }
    $cmd .= " >/var/log/oci.log 2>&1 &";

    $out["cmd"] = $cmd;
    return $out;
}

// Calculate a /etc/hosts file containing the IP and names
// of the slave host itself, and all its peers in the cluster
function slave_calculate_hosts_file($con, $conf, $machine_id){
    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out .= "Cannot find machine: $machine_id<br>";
        return $out;
    }
    $machine = mysqli_fetch_array($r);
    $machine_fqdn     = $machine["hostname"];
    $machine_cluster  = $machine["cluster"];
    $machine_ipaddr   = $machine["ipaddr"];
    $machine_role     = $machine["role"];

    if(!is_null($machine_cluster)){
        $q = "SELECT * FROM clusters WHERE id='$machine_cluster'";
        $r = mysqli_query($con, $q);
        $n = mysqli_num_rows($r);
        if($n != 1){
            $out .= "Cannot find machine: $machine_id<br>";
            return $out;
        }
        $cluster = mysqli_fetch_array($r);
        $cluster_domain       = $cluster["domain"];
        $cluster_id           = $cluster["id"];
        $cluster_name         = $cluster["name"];
        $cluster_vip_hostname = $cluster["vip_hostname"];
        if($cluster_vip_hostname == ""){
            $cluster_vip_hostname = $cluster_name ."-api." . $cluster_domain;
        }

        // Remove the hostname from the machine's FQDN
        $machine_hostname = str_replace("." . $cluster_domain, "", $machine_fqdn);

        $q = "SELECT INET_NTOA(ip) AS addr FROM ips WHERE machine='$machine_id' LIMIT 1";
        $r = mysqli_query($con, $q);
        $n = mysqli_num_rows($r);
        if($n >= 1){
            $ip = mysqli_fetch_array($r);
            $machine_ipaddr = $ip["addr"];
        }
    }else{
        $machine_hostname = $machine_fqdn;
    }

    $pxe_server_hostname = gethostname();
    $pxe_server_ipaddr = $conf["network"]["OCI_IP"];

    $out = "127.0.0.1	localhost
$machine_ipaddr	$machine_fqdn $machine_hostname

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

# The puppet master:
$pxe_server_ipaddr	$pxe_server_hostname
";

    $out .= "# VIP address:
";

    // Fetch the VIP ip
    if(!is_null($machine_cluster)){
        $q = "SELECT * FROM networks WHERE cluster='$machine_cluster' AND is_public='yes' AND (role='all' OR role='controller') LIMIT 1";
        $r = mysqli_query($con, $q);
        $n = mysqli_num_rows($r);
        if($n == 1){
            $network = mysqli_fetch_array($r);
            $network_id   = $network["id"];
            $network_cidr = $network["cidr"];
            if($network_cidr == "32"){
                $vip_addr = $network["ip"];
                $out .= $vip_addr ." " . $cluster_name ."-api." . $cluster_domain . "\n";
            }else{
                $q = "SELECT INET_NTOA(ip) AS addr FROM ips WHERE network='$network_id' AND usefor='vip'";
                $r = mysqli_query($con, $q);
                $n = mysqli_num_rows($r);
                if($n == 1){
                    $vip = mysqli_fetch_array($r);
                    $vip_addr = $vip["addr"];
                    $out .= $vip_addr ." " . $cluster_name ."-api." . $cluster_domain . "\n";
                }
            }
        }
    }

    $out .= "# Nodes in this cluster:
";
    if(!is_null($machine_cluster)){
        $q = "SELECT * FROM machines WHERE cluster='$machine_cluster' AND id != '$machine_id'";
        $r = mysqli_query($con, $q);
        $n = mysqli_num_rows($r);
        for($i=0;$i<$n;$i++){
            $other_host = mysqli_fetch_array($r);
            $other_host_ipaddr   = $other_host["ipaddr"];
            $other_host_fqdn     = $other_host["hostname"];
            $other_host_hostname = str_replace("." . $cluster_domain, "", $other_host_fqdn);
            $other_host_id       = $other_host["id"];

            $q_oh = "SELECT INET_NTOA(ips.ip) AS addr FROM networks, ips WHERE ips.machine='$other_host_id' AND networks.cluster='$machine_cluster' AND networks.id=ips.network LIMIT 1";
            $r_oh = mysqli_query($con, $q_oh);
            $n_oh = mysqli_num_rows($r_oh);
            if($n_oh == 1){
                $ip_oh = mysqli_fetch_array($r_oh);
                $other_host_ipaddr = $ip_oh["addr"];
            }
            $out .= "$other_host_ipaddr	$other_host_fqdn $other_host_hostname\n";
        }
    }
    return $out;
}

function build_swift_ring($con, $conf, $cluster_id, $verbose="no"){
    $out = "";
    $q = "SELECT * FROM clusters WHERE id='$cluster_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out .= "Cannot find cluster: $cluster_id<br>";
        return $out;
    }
    $cluster = mysqli_fetch_array($r);
    $cluster_name = $cluster["name"];
    $cluster_swift_part_power     = $cluster["swift_part_power"];
    $cluster_swift_replicas       = $cluster["swift_replicas"];
    $cluster_swift_min_part_hours = $cluster["swift_min_part_hours"];

    #################################################
    ### Create the swift ring if it doesn't exist ###
    #################################################
    # First, we check if there's some swiftstore machines in the cluster, in which case
    # we do need a swift ring.

    if(!is_dir("/var/lib/oci/clusters")){
        mkdir("/var/lib/oci/clusters", 0755);
    }
    if(!is_dir("/var/lib/oci/clusters/$cluster_name")){
        mkdir("/var/lib/oci/clusters/$cluster_name", 0755);
    }


    $swift_ring_path = "/var/lib/oci/clusters/$cluster_name/swift-ring";
    if(!is_dir($swift_ring_path)){
        mkdir($swift_ring_path, 0755);
    }

    # Account
    $cmd = "swift-ring-builder $swift_ring_path/account.builder create $cluster_swift_part_power $cluster_swift_replicas $cluster_swift_min_part_hours";
    if($verbose == "yes"){ print("Creating account.builder ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Creating account.builder ring:\n   ===> $cmd\n";}
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    # Container
    $cmd = "swift-ring-builder $swift_ring_path/container.builder create $cluster_swift_part_power $cluster_swift_replicas $cluster_swift_min_part_hours";
    if($verbose == "yes"){ print("Creating container.builder ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Creating container.builder ring:\n   ===> $cmd\n";}
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    # Object
    $cmd = "swift-ring-builder $swift_ring_path/object.builder create $cluster_swift_part_power $cluster_swift_replicas $cluster_swift_min_part_hours";
    if($verbose == "yes"){ print("Creating object.builder ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Creating object.builder ring:\n   ===> $cmd\n";}
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);


    $q = "SELECT machines.hostname AS hostname, INET_NTOA(ips.ip) AS ipaddr, blockdevices.name AS hddname, machines.location_id AS locationid FROM ips,machines,blockdevices WHERE machines.cluster='$cluster_id' AND machines.role='swiftstore' AND machines.id=blockdevices.machine_id AND ips.machine=machines.id AND name NOT LIKE '%da' ORDER BY ips.ip, blockdevices.name";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    $last_ip = "";
    for($i=0;$i<$n;$i++){
        $blockdev = mysqli_fetch_array($r);
        $blockdev_locationid = $blockdev["locationid"];
        $blockdev_ipaddr     = $blockdev["ipaddr"];
        $blockdev_devicename = $blockdev["hddname"];
        $hostname            = $blockdev["hostname"];

        $q = "SELECT swiftregions.id AS swiftregion FROM locations,swiftregions WHERE locations.id='$blockdev_locationid' AND swiftregions.name=locations.swiftregion";
        $rsw = mysqli_query($con, $q);
        $nsw = mysqli_num_rows($rsw);
        if($nsw == 0){
            $swiftregion = "0";
        }else{
            $asr = mysqli_fetch_array($rsw);
            $swiftregion = $asr["swiftregion"] + 1;
        }
  
        # Account
        $cmd = "swift-ring-builder $swift_ring_path/account.builder add --region $swiftregion --zone $blockdev_locationid --ip $blockdev_ipaddr --port 6002 --device $blockdev_devicename --weight 100";
        if($verbose == "yes"){ print("Adding $hostname, $blockdev_devicename to the account ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Adding $hostname, $blockdev_devicename to the account ring:\n   ===> $cmd\n";}
        $output = array();
        $return_var = 0;
        exec($cmd, $output, $return_var);

        # Container
        $cmd = "swift-ring-builder $swift_ring_path/container.builder add --region $swiftregion --zone $blockdev_locationid --ip $blockdev_ipaddr --port 6001 --device $blockdev_devicename --weight 100";
        if($verbose == "yes"){ print("Adding $hostname, $blockdev_devicename to the container ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Adding $hostname, $blockdev_devicename to the container ring:\n   ===> $cmd\n";}
        $output = array();
        $return_var = 0;
        exec($cmd, $output, $return_var);

        # Object
        if($blockdev_ipaddr != $last_ip){
            $blockdev_object_port = 6200;
        }else{
            $blockdev_object_port += 1;
        }
        $last_ip = $blockdev_ipaddr;
        $cmd = "swift-ring-builder $swift_ring_path/object.builder add --region $swiftregion --zone $blockdev_locationid --ip $blockdev_ipaddr --port $blockdev_object_port --device $blockdev_devicename --weight 100";
        if($verbose == "yes"){ print("Adding $hostname, $blockdev_devicename to the object ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Adding $hostname, $blockdev_devicename to the object ring:\n   ===> $cmd\n";}
        $output = array();
        $return_var = 0;
        exec($cmd, $output, $return_var);
    }

    # Account
    $cmd = "swift-ring-builder $swift_ring_path/account.builder rebalance";
    if($verbose == "yes"){ print("Rebalancing account ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Rebalancing account ring:\n   ===> $cmd\n";}
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    # Container
    $cmd = "swift-ring-builder $swift_ring_path/container.builder rebalance";
    if($verbose == "yes"){ print("Rebalancing container ring: $cmd<br>"); ob_flush(); }else{ $out .= "Rebalancing container ring:\n   ===> $cmd\n";}
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    # Object
    $cmd = "swift-ring-builder $swift_ring_path/object.builder rebalance";
    if($verbose == "yes"){ print("Rebalancing object ring: $cmd<br>\n"); ob_flush(); }else{ $out .= "Rebalancing object ring:\n   ===> $cmd\n";}
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);
    if($verbose == "yes"){ print("All done!"); }else{ $out .= "All done!";}

    $q = "SELECT machines.hostname AS hostname, INET_NTOA(ips.ip) AS ipaddr FROM ips,machines WHERE machines.cluster='$cluster_id' AND (machines.role='swiftstore' OR machines.role='swiftproxy') AND ips.machine=machines.id ORDER BY ips.ip";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    $script = "#!/bin/sh
set -e

";
    for($i=0;$i<$n;$i++){
        $machine = mysqli_fetch_array($r);
        $ipaddr   = $machine["ipaddr"];
        $hostname = $machine["hostname"];
        $script .= "echo \"===> Copying ring to: $hostname\"\n";
        $script .= "scp $swift_ring_path/account.ring.gz $swift_ring_path/container.ring.gz $swift_ring_path/object.ring.gz $ipaddr:/etc/swift\n";
        $script .= "ssh $ipaddr \"chown swift:swift /etc/swift/account.ring.gz /etc/swift/container.ring.gz /etc/swift/object.ring.gz\"\n";
    }
    file_put_contents("$swift_ring_path/scp-ring", $script);
    chmod("$swift_ring_path/scp-ring", "w+x");

    return $out;
}

function ipmi_set_boot_device($con, $conf, $machine_id, $bootdev){
    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out .= "Cannot find machine: $machine_id<br>";
        return $out;
    }
    $machine = mysqli_fetch_array($r);

    $ipmi_use                  = $machine["ipmi_use"];
    $ipmi_call_chassis_bootdev = $machine["ipmi_call_chassis_bootdev"];
    $ipmi_addr                 = $machine["ipmi_addr"];
    $ipmi_port                 = $machine["ipmi_port"];
    $ipmi_username             = $machine["ipmi_username"];
    $ipmi_password             = $machine["ipmi_password"];

    if($ipmi_use == "yes" && $ipmi_call_chassis_bootdev == "yes"){
        $cmd = "ipmitool -I lanplus -H $ipmi_addr -p $ipmi_port -U $ipmi_username -P $ipmi_password chassis bootdev $bootdev options=persistent";
        $output = "";
        $return_var = 0;
        exec($cmd, $output, $return_var);
    }
}

function slave_install_os($con, $conf, $machine_id, $install_cmd){
    $q = "SELECT * FROM machines WHERE id='$machine_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out .= "Cannot find machine: $machine_id<br>";
        return $out;
    }
    $machine = mysqli_fetch_array($r);
    $machine_ipaddr   = $machine["ipaddr"];
    $machine_hostname = $machine["hostname"];
    $machine_role     = $machine["role"];
    $cluster_id       = $machine["cluster"];

    // Set boot device if using that IPMI option
    ipmi_set_boot_device($con, $conf, $machine_id, "disk");

    $q = "SELECT * FROM clusters WHERE id='$cluster_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out .= "Cannot find cluster: $cluster_id<br>";
        return $out;
    }
    $cluster = mysqli_fetch_array($r);
    $cluster_name = $cluster["name"];

    #######################################################
    ### Create a folder for filesystem template of host ###
    #######################################################
    $template_path = "/var/lib/oci/clusters/$cluster_name/$machine_hostname";
    if(!is_dir("/var/lib/oci/clusters")){
        mkdir("/var/lib/oci/clusters", 0755);
    }
    if(!is_dir("/var/lib/oci/clusters/$cluster_name")){
        mkdir("/var/lib/oci/clusters/$cluster_name", 0755);
    }
    if(!is_dir("/var/lib/oci/clusters/$cluster_name/$machine_hostname")){
        mkdir("/var/lib/oci/clusters/$cluster_name/$machine_hostname", 0755);
    }

    #########################
    ### Manage /etc/hosts ###
    #########################
    // Calculate and scp the /etc/hosts file
    $host_file = slave_calculate_hosts_file($con, $conf, $machine_id);
    file_put_contents("$template_path/oci-hosts-file", $host_file);

    #################################################################
    ### Manage puppet-master hostname file and client certificate ###
    #################################################################
    // Send the puppet-master hostname to /puppet-master-host
    file_put_contents("$template_path/puppet-master-host", gethostname());

    // Delete a probably already existing cert
    $cmd = "sudo /usr/bin/puppet cert clean $machine_hostname";
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    // Generate puppet certificates
    $cmd = "sudo /usr/bin/puppet ca generate $machine_hostname";
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    $cmd = "sudo /usr/bin/oci-copy-slave-node-generate-key $machine_hostname $template_path 2>&1";
    exec($cmd, $output, $return_var);

    # We keep only the signed certificate, everything else can
    # go away from the puppet-master.
    $cmd = "sudo /usr/bin/oci-remove-slave-node-generated-key $machine_hostname";
    exec($cmd, $output, $return_var);

    #######################################################
    ### Manage PKI x509 slave node certificate and keys ###
    #######################################################
    # Copy all of the CA's .pem files
    $ca_pem_dir = "/var/lib/oci/ssl/ca";
    if (is_dir($ca_pem_dir)) {
        if ($dh = opendir($ca_pem_dir)) {
            while (($file = readdir($dh)) !== false) {
                if(filetype($ca_pem_dir . "/" . $file) == "file"){
                    copy("$ca_pem_dir/$file", "$template_path/$file");
                }
            }
            closedir($dh);
        }
    }

    # Copy the server's private/public keypair
    $node_keys_dir = "/var/lib/oci/ssl/slave-nodes/$machine_hostname";
    if (is_dir($node_keys_dir)) {
        if ($dh = opendir($node_keys_dir)) {
            while (($file = readdir($dh)) !== false) {
                if(filetype($node_keys_dir . "/" . $file) == "file"){
                    copy("$node_keys_dir/$file", "$template_path/$file");
                }
            }
            closedir($dh);
        }
    }

    # If the machine is a controller, then haproxy will need the API SSL keys
    # to be used in haproxy.
    $api_keys = "/var/lib/oci/ssl/slave-nodes/$machine_hostname";
    $q = "SELECT * FROM clusters WHERE id='$cluster_id'";
    $r = mysqli_query($con, $q);
    $n = mysqli_num_rows($r);
    if($n != 1){
        $out .= "Cannot find machine: $machine_id<br>";
        return $out;
    }
    $cluster = mysqli_fetch_array($r);
    $cluster_name            = $cluster["name"];
    $cluster_domain          = $cluster["domain"];
    $cluster_vip_hostname    = $cluster["vip_hostname"];
    $first_master_machine_id = $cluster["first_master_machine_id"];
    $cluster_swift_proxy_hostname = $cluster["swift_proxy_hostname"];

    if($cluster_vip_hostname == ""){
        $api_hostname = $cluster_name . "-api." . $cluster_domain;
    }else{
        $api_hostname = $cluster_vip_hostname;
    }

    # Copy the API key
    $api_keys_dir = "/var/lib/oci/ssl/slave-nodes/$api_hostname";
    if (is_dir($api_keys_dir)) {
        if ($dh = opendir($api_keys_dir)) {
            while (($file = readdir($dh)) !== false) {
                if(filetype($api_keys_dir . "/" . $file) == "file"){
                    switch($file){
                    case "$api_hostname.key":
                        // Only controllers need the private key
                        if($machine_role == "controller"){
                            copy("$api_keys_dir/$file", "$template_path/oci-pki-api.key");
                        }
                        break;
                    case "$api_hostname.crt":
                        // But everyone needs the cert
                        copy("$api_keys_dir/$file", "$template_path/oci-pki-api.crt");
                        break;
                    case "$api_hostname.csr":
                        // But everyone needs the cert
                        copy("$api_keys_dir/$file", "$template_path/oci-pki-api.csr");
                        break;
                    case "$api_hostname.pem":
                        // But everyone needs the cert
                        copy("$api_keys_dir/$file", "$template_path/oci-pki-api.pem");
                        break;
                    default:
                        break;
                    }
                }
            }
            closedir($dh);
        }
    }

    $swift_ring_path = "/var/lib/oci/clusters/$cluster_name/swift-ring";

    if(file_exists("$swift_ring_path/account.ring.gz") === FALSE || file_exists("$swift_ring_path/container.ring.gz") === FALSE ||file_exists("$swift_ring_path/object.ring.gz") === FALSE){
        build_swift_ring($con, $conf, $cluster_id);
    }

    mkdir("$template_path/oci-in-target");
    mkdir("$template_path/oci-in-target/etc");
    $motd_content = "

Welcome to $machine_hostname.
This OS was installed using OCI:
https://salsa.debian.org/openstack-team/debian/openstack-cluster-installer

";
    file_put_contents("$template_path/oci-in-target/etc/motd", $motd_content);
    if($machine_role == "swiftstore" || $machine_role == "swiftproxy"){
        mkdir("$template_path/oci-in-target/etc/swift");
        copy("$swift_ring_path/account.ring.gz", "$template_path/oci-in-target/etc/swift/account.ring.gz");
        copy("$swift_ring_path/container.ring.gz", "$template_path/oci-in-target/etc/swift/container.ring.gz");
        copy("$swift_ring_path/object.ring.gz", "$template_path/oci-in-target/etc/swift/object.ring.gz");
    }

    # Copy the cert+key if using a custom swiftproxy URL
    if($machine_role == "swiftproxy"){
        if($cluster_swift_proxy_hostname != ""){
            $swift_proxy_key_dir = "/var/lib/oci/ssl/slave-nodes/$cluster_swift_proxy_hostname";
            if (is_dir($swift_proxy_key_dir)) {
                if ($dh = opendir($swift_proxy_key_dir)) {
                    while (($file = readdir($dh)) !== false) {
                        if(filetype($swift_proxy_key_dir . "/" . $file) == "file"){
                            switch($file){
                            case "$cluster_swift_proxy_hostname.key":
                                copy("$swift_proxy_key_dir/$file", "$template_path/oci-pki-swiftproxy.key");
                                break;
                            case "$cluster_swift_proxy_hostname.crt":
                                copy("$swift_proxy_key_dir/$file", "$template_path/oci-pki-swiftproxy.crt");
                                break;
                            case "$cluster_swift_proxy_hostname.csr":
                                copy("$swift_proxy_key_dir/$file", "$template_path/oci-pki-swiftproxy.csr");
                                break;
                            case "$cluster_swift_proxy_hostname.pem":
                                copy("$swift_proxy_key_dir/$file", "$template_path/oci-pki-swiftproxy.pem");
                                break;
                            }
                        }
                    }
                }
            }
        }
    }

    ###########################################################
    ### Copy the cluster's ssh keypair if it's a controller ###
    ###########################################################
    if($machine_role == "controller"){
        $ssh_key_dir = "/var/lib/oci/clusters/$cluster_name/ssh";
        if(file_exists("$ssh_key_dir/id_rsa")){
            mkdir("$template_path/oci-in-target/root");
            mkdir("$template_path/oci-in-target/root/.ssh", 0700);
            copy("$ssh_key_dir/id_rsa", "$template_path/oci-in-target/root/.ssh/id_rsa");
            if(file_exists("$ssh_key_dir/id_rsa.pub")){
                copy("$ssh_key_dir/id_rsa.pub", "$template_path/oci-in-target/root/.ssh/id_rsa.pub");
            }
        }
        # Add fernet rotation script if it's the first master server
        if($machine_id == $first_master_machine_id){
            mkdir("$template_path/oci-in-target/etc/cron.weekly");
            copy("/usr/bin/oci-fernet-keys-rotate", "$template_path/oci-in-target/etc/cron.weekly/oci-fernet-keys-rotate");
        }
    }

    ##################################################################
    ### If the machine is a swiftstore, we need the facts.d helper ###
    ##################################################################
    if($machine_role == "swiftstore"){
        mkdir("$template_path/oci-in-target/etc/facter");
        mkdir("$template_path/oci-in-target/etc/facter/facts.d");
        copy("/etc/facter/facts.d/swift_blockdevs_names_to_uuid.sh", "$template_path/oci-in-target/etc/facter/facts.d/swift_blockdevs_names_to_uuid.sh");
    }

    ###########################################################################
    ### Create a tarball from the $template_path folder, scp it, extract it ###
    ###########################################################################
    $cmd = "cd /var/lib/oci/clusters/$cluster_name/$machine_hostname && tar -C /var/lib/oci/clusters/$cluster_name/$machine_hostname -cvzf /var/lib/oci/clusters/$cluster_name/$machine_hostname.tar.gz *";
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var);

    scp_a_file($conf, $con, $machine_ipaddr, "/var/lib/oci/clusters/$cluster_name/$machine_hostname.tar.gz", "/oci-to-extract-tarball.tar.gz", 0644);
    $ret = send_ssh_cmd($conf, $con, $machine_ipaddr, "tar -C / -xvzf /oci-to-extract-tarball.tar.gz");

    #####################################
    ### Perform the actual OS install ###
    #####################################
    $ret = send_ssh_cmd($conf, $con, $machine_ipaddr, $install_cmd);
}

?>
