restype = 'computer';
$this->restypename = 'Computer';
$this->namefield = 'hostname';
$this->defaultGetDataArgs = array('sort' => 0,
'includedeleted' => 0,
'rscid' => '');
$this->basecdata['obj'] = $this;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn getData($args)
///
/// \param $args - array of arguments that determine what data gets returned;
/// must include:\n
/// \param $sort - (optional) 1 to sort computers; 0 not to
/// \b includedeleted - 0 or 1; include deleted images\n
/// \b rscid - only return data for resource with this id; pass 0 for all
/// (from image table)
///
/// \return array of data as returned from getImages
///
/// \brief wrapper for calling getImages
///
/////////////////////////////////////////////////////////////////////////////
function getData($args) {
return getComputers($args['sort'], $args['includedeleted'], $args['rscid']);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn fieldWidth($field)
///
/// \param $field - name of a resource field
///
/// \return string for setting width of field (includes width= part)
///
/// \brief generates the required width for the field; can return an empty
/// string if field should default to auto width
///
/////////////////////////////////////////////////////////////////////////////
function fieldWidth($field) {
switch($field) {
case 'currentimg':
case 'nextimg':
$w = 17;
break;
case 'notes':
$w = 14;
break;
case 'IPaddress':
case 'privateIPaddress':
case 'natpublicIPaddress':
case 'natinternalIPaddress':
$w = 8;
break;
case 'eth0macaddress':
case 'eth1macaddress':
$w = 8.5;
break;
case 'vmhost':
case 'nathost':
$w = 8;
break;
case 'type':
$w = 7;
break;
case 'location':
$w = 9;
break;
case 'predictivemodule':
$w = 10;
break;
case 'provisioning':
$w = 11;
break;
case 'owner':
$w = 12;
break;
default:
return '';
}
if(preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT']) ||
preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT']))
$w = round($w * 11.5) . 'px';
else
$w = "{$w}em";
return "width=\"$w\"";
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn fieldDisplayName($field)
///
/// \param $field - name of a resource field
///
/// \return display value for $field
///
/// \brief generates the display value for $field
///
/////////////////////////////////////////////////////////////////////////////
function fieldDisplayName($field) {
switch($field) {
case 'currentimg':
return 'Current Image';
case 'nextimg':
return 'Next Image';
case 'ram':
return 'RAM';
case 'procnumber':
return 'Cores';
case 'procspeed':
return 'Processor speed';
case 'network':
return 'Network speed';
case 'IPaddress':
return 'Public IP Address';
case 'privateIPaddress':
return 'Private IP Address';
case 'eth0macaddress':
return 'Private MAC Address';
case 'eth1macaddress':
return 'Public MAC Address';
case 'vmhost':
return 'VM Host';
case 'provisioning':
return 'Provisioning Engine';
case 'predictivemodule':
return 'Predictive Loading Module';
case 'natenabled':
return 'Connect Using NAT';
case 'nathost':
return 'NAT Host';
case 'nathostenabled':
return 'Use as NAT Host';
case 'natpublicIPaddress':
return 'NAT Public IP Address';
case 'natinternalIPaddress':
return 'NAT Internal IP Address';
}
return ucfirst($field);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn extraSelectAdminOptions()
///
/// \return html
///
/// \brief generates HTML for option to create/update an image
///
/////////////////////////////////////////////////////////////////////////////
function extraSelectAdminOptions() {
$h = '';
$h .= " (Computer Utilities are now incorporated into Edit Computer ";
$h .= "Profiles) \n";
return $h;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn extraResourceFilters()
///
/// \return html
///
/// \brief generates HTML for computer utilities drop down and filtering by
/// computer group
///
/////////////////////////////////////////////////////////////////////////////
function extraResourceFilters() {
$h = '';
# selected items menu
$h .= "
\n";
$h .= "NOTE: 'Start IP' and 'End IP' can only differ in the number ";
$h .= "after the last '.'. The hostnames will be generated from the ";
$h .= "'Hostname' field. The hostnames for each computer can only differ ";
$h .= "by the value of a number in the first part of the hostname. Place ";
$h .= "a '%' character in the 'Hostname' field where that number will be. ";
$h .= "Then fill in 'Start value' and 'End value' with the first and last ";
$h .= "values to be used in the hostname.
";
$h .= "
\n"; # multiplenotediv
# div for canceling moving blade to vmhostinuse
$h .= "
\n";
$h .= "\n";
$h .= "NOTICE: This computer is scheduled to start being reloaded as a vmhost at ";
$h .= "";
$h .= ". You may cancel this scheduled reload by clicking the button below.";
$h .= "
\n";
$h .= "\n";
$h .= "NOTICE: This computer is currently being reloaded as a vmhost. You may cancel this ";
$h .= "process by clicking on the button below. After canceling the reload, it may take several ";
$h .= "minutes for the cancellation process to complete.";
$h .= "
\n";
$h .= "\n";
$h .= "\n";
$h .= "
\n"; # cancelvmhostinusediv
$h .= "\n";
# hostname
$errmsg = _("Name can only contain letters, numbers, dashes(-), periods(.), and underscores(_). It can be from 1 to 36 characters long.");
$h .= labeledFormItem('name', _('Name') . '*', 'text', '^([a-zA-Z0-9_][-a-zA-Z0-9_\.]{1,35})$',
1, '', $errmsg);
# start/end
$h .= "
\n";
# public IP
$ipreg = '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)';
$ipreg1 = "^$ipreg$";
$errmsg = _("Invalid Public IP address specified - must be a valid IPV4 address");
$h .= labeledFormItem('ipaddress', _('Public IP Address') . '*', 'text', $ipreg1, 1, '', $errmsg);
# private IP
$errmsg = _("Invalid Private IP address specified - must be a valid IPV4 address");
$h .= labeledFormItem('privateipaddress', _('Private IP Address'), 'text', $ipreg1, 0, '', $errmsg);
# Public MAC
$macreg = '^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$';
$errmsg = _("Invalid Public MAC address specified");
$h .= labeledFormItem('publicmac', _('Public MAC Address'), 'text', $macreg, 0, '', $errmsg);
# private MAC
$errmsg = _("Invalid Private MAC address specified");
$h .= labeledFormItem('privatemac', _('Private MAC Address'), 'text', $macreg, 0, '', $errmsg);
$h .= "
\n"; # singleipmacdiv
# multi computer fields
$h .= "
\n";
# start public IP
$errmsg = _("Invalid Start Public IP Address specified - must be a valid IPV4 address");
$h .= labeledFormItem('startpubipaddress', _('Start Public IP Address') . '*', 'text', $ipreg1, 1, '', $errmsg);
# end public IP
$errmsg = _("Invalid End Public IP Address specified - must be a valid IPV4 address");
$h .= labeledFormItem('endpubipaddress', _('End Public IP Address') . '*', 'text', $ipreg1, 1, '', $errmsg);
# start private IP
$errmsg = _("Invalid Start Private IP Address specified - must be a valid IPV4 address");
$h .= labeledFormItem('startprivipaddress', _('Start Private IP Address') . '*', 'text', $ipreg1, 1, '', $errmsg);
# end private IP
$errmsg = _("Invalid End Private IP Address specified - must be a valid IPV4 address");
$h .= labeledFormItem('endprivipaddress', _('End Private IP Address') . '*', 'text', $ipreg1, 1, '', $errmsg);
# start MAC
$errmsg = _("Invalid Start MAC Address specified");
$h .= labeledFormItem('startmac', _('Start MAC Address'), 'text', $macreg, 0, '', $errmsg);
$h .= "
\n";
# use as NAT host
$extra = array('onChange' => "toggleNAThost();");
$h .= labeledFormItem('nathostenabled', _('Use as NAT Host'), 'check', '', '', '1', '', '', $extra);
# public IP
$errmsg = _("Invalid NAT Public IP address specified - must be a valid IPV4 address");
$h .= labeledFormItem('natpublicipaddress', _('NAT Public IP Address'), 'text', $ipreg1, 1, '', $errmsg);
# internal IP
$errmsg = _("Invalid NAT Internal IP address specified - must be a valid IPV4 address");
$h .= labeledFormItem('natinternalipaddress', _('NAT Internal IP Address'), 'text', $ipreg1, 1, '', $errmsg);
$h .= "
\n"; # NAT Host
# compid
$h .= "
\n";
$h .= "\n";
$h .= " \n";
$h .= "
\n";
# location
$errmsg = _("Location can be up to 255 characters long and may contain letters, numbers, spaces, and these characters: - , . _ @ # ( )");
$h .= labeledFormItem('location', _('Location'), 'text',
'^([-a-zA-Z0-9_\. ,@#\(\)]{0,255})$', 0, '', $errmsg);
$h .= "
Schedule the computer to be reloaded with the selected ";
$msg .= "profile at $end
\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$msg = preg_replace("|$end|", "$end", $msg, 1);
$promptuser = 1;
$cdata = $this->basecdata;
$cdata['maintenanceonly'] = 0;
$cdata['compid'] = $data['rscid'];
$cdata['reloadstart'] = $reloadstart;
$cdata['imageid'] = $imageid;
$cdata['oldprofileid'] = $olddata['vmprofileid'];
$cdata['vmprofileid'] = $data['vmprofileid'];
$cdata['newstateid'] = $data['stateid'];
$cdata['oldstateid'] = $olddata['stateid'];
$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
$btntxt = 'Schedule Reload';
$title = 'Delayed State Change';
}
else {
# no reservations
$start = getReloadStartTime();
$checkstart = getExistingChangeStateStartTime($data['rscid'], 21);
if($checkstart && $checkstart < $start)
$start = $checkstart;
$rc = $this->scheduleTovmhostinuse($data['rscid'], $imageid, $start,
$data['vmprofileid'], $olddata['vmprofileid']);
if($rc == 0) {
$msg = '';
if(count($updates))
$msg .= "Computer information changes were saved. \nHowever, a ";
else
$msg .= "A ";
$msg .= "problem was encountered while attempting to reload the ";
$msg .= "computer with the selected VM Host Profile. Please try ";
$msg .= "again at a later time.\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$promptuserfail = 1;
$title = 'VM Host Reload Failed';
}
else
$multirefresh = 3;
}
$data['stateid'] = $olddata['stateid']; # prevent state from being updated directly
}
else {
# manually provisioned
if($reloadstart) {
# reservations, must wait until end time
$end = date('n/j/y g:i a', $reloadstart);
$msg = '';
if(count($updates))
$msg .= "Computer information changes saved. \nHowever, this ";
else
$msg .= "This ";
$msg .= "computer is currently allocated until $end and cannot ";
$msg .= "be converted to a VM host until then. You can:\n";
$msg .= "
Cancel and do nothing
\n";
$msg .= "
Schedule the computer to go in to maintenance at $end ";
$msg .= "and manually move it to vmhostinuse after that
\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$msg = preg_replace("|$end|", "$end", $msg, 1);
$promptuser = 1;
$cdata = $this->basecdata;
$cdata['maintenanceonly'] = 1;
$cdata['reloadstart'] = $reloadstart;
$cdata['imageid'] = getImageId('noimage');
$cdata['compid'] = $data['rscid'];
$cdata['newstateid'] = $data['stateid'];
$cdata['oldstateid'] = $olddata['stateid'];
$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
$btntxt = 'Schedule State Change';
$title = 'Delayed State Change';
$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
}
else {
# no reservations
$this->updateVmhostProfile($data['rscid'], $data['vmprofileid'], $olddata['vmprofileid']);
}
}
}
elseif($olddata['stateid'] == 20 && $data['stateid'] == 2) {
# only valid condition for VCL provisioned
# check for reservations
moveReservationsOffVMs($data['rscid']);
cleanSemaphore();
$reloadstart = getCompFinalVMReservationTime($data['rscid'], 1);
if($reloadstart == -1) {
$msg = '';
if(count($updates))
$msg .= "Computer information changes were saved. \nHowever, a ";
else
$msg .= "A ";
$msg .= "problem was encountered while attempting to move VMs ";
$msg .= "off of the computer. Please try again at a later time.\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$promptuserfail = 1;
$title = 'Change to Available Failed';
$data['stateid'] = $olddata['stateid'];
}
elseif($reloadstart > 0) {
cleanSemaphore();
$end = date('n/j/y g:i a', $reloadstart);
$msg = '';
if(count($updates))
$msg .= "Computer information changes saved. \nHowever, this ";
else
$msg .= "This ";
$msg .= "computer currently has VMs with reservations on them until ";
$msg .= "$end and cannot be moved to the available state until then. ";
$msg .= "You can:\n";
$msg .= "
Cancel and do nothing
\n";
$msg .= "
Schedule the VMs to be removed at $end and the computer ";
$msg .= "to be moved to available that
\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$msg = preg_replace("|$end|", "$end", $msg, 1);
$promptuser = 1;
$cdata = $this->basecdata;
$cdata['reloadstart'] = $reloadstart;
$cdata['imageid'] = getImageId('noimage');
$cdata['compid'] = $data['rscid'];
$cdata['newstateid'] = $data['stateid'];
$cdata['oldstateid'] = $olddata['stateid'];
$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
$btntxt = 'Schedule State Change';
$title = 'Delayed State Change';
$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
}
else {
# schedule tomaintenance reservations for VMs
# might be better to just directly move the VMs to the maintenance state
$vclreloadid = getUserlistID('vclreload@Local');
$imageid = getImageId('noimage');
$revid = getProductionRevisionid($imageid);
$start = getReloadStartTime();
$end = $start + SECINMONTH;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
$query = "SELECT vm.id "
. "FROM computer vm, "
. "vmhost v "
. "WHERE v.computerid = {$data['rscid']} AND "
. "vm.vmhostid = v.id";
$qh = doQuery($query);
$fail = 0;
while($row = mysql_fetch_assoc($qh)) {
if(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
$enddt, 18, $vclreloadid)) {
$fail = 1;
break;
}
else
$multirefresh = 2;
}
cleanSemaphore();
if($fail) {
$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
$msg = '';
if(count($updates))
$msg .= "Computer information changes were saved. \nHowever, a ";
else
$msg .= "A ";
$msg .= "problem was encountered while attempting to remove VMs ";
$msg .= "from the computer. Please try again at a later time.\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$promptuserfail = 1;
$title = 'Change State to Available Failed';
}
}
}
elseif($olddata['stateid'] == 20 && $data['stateid'] == 10) {
# VCL provisioned and manually provisioned are the same
# check for reservations
moveReservationsOffVMs($data['rscid']);
cleanSemaphore();
$reloadstart = getCompFinalVMReservationTime($data['rscid'], 1, 1);
if($reloadstart == -1) {
$msg = '';
if(count($updates))
$msg .= "Computer information changes were saved. \nHowever, a ";
else
$msg .= "A ";
$msg .= "problem was encountered while attempting to place assigned VMs ";
$msg .= "into the maintenance state. Please try again at a later time.\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$promptuserfail = 1;
$title = 'Change to Maintenance Failed';
}
elseif($reloadstart > 0) {
cleanSemaphore();
if(unixToDatetime($reloadstart) == '2038-01-01 00:00:00') {
$msg = '';
if(count($updates))
$msg .= "Computer information changes saved. \nHowever, this ";
else
$msg .= "This ";
$msg .= "computer currently has VMs assigned to it that have server ";
$msg .= "reservations with indefinite endings. The computer cannot ";
$msg .= "be moved to the maintenance state while these reservations exist.";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$promptuserfail = 1;
$title = 'Change to Maintenance Failed';
$data['stateid'] = $olddata['stateid']; # prevent state from being updated
}
else {
$end = date('n/j/y g:i a', $reloadstart);
$msg = '';
if(count($updates))
$msg .= "Computer information changes saved. \nHowever, this ";
else
$msg .= "This ";
$msg .= "computer currently has VMs with reservations on them until ";
$msg .= "$end and cannot be moved to the maintenance state until then. ";
$msg .= "You can:\n";
$msg .= "
Cancel and do nothing
\n";
$msg .= "
Schedule the computer and VMs to be moved into the ";
$msg .= "maintenance state at $end
\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$msg = preg_replace("|$end|", "$end", $msg, 1);
$promptuser = 1;
$cdata = $this->basecdata;
$cdata['reloadstart'] = $reloadstart;
$cdata['imageid'] = getImageId('noimage');
$cdata['compid'] = $data['rscid'];
$cdata['newstateid'] = $data['stateid'];
$cdata['oldstateid'] = $olddata['stateid'];
$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
$btntxt = 'Schedule State Change';
$title = 'Delayed State Change';
$data['stateid'] = $olddata['stateid']; # prevent state from being updated yet
}
}
else {
$query = "UPDATE computer c "
. "INNER JOIN vmhost v ON (c.vmhostid = v.id) "
. "SET c.stateid = 10, "
. "c.notes = 'maintenance with host {$data['rscid']}' "
. "WHERE v.computerid = {$data['rscid']}";
doQuery($query);
cleanSemaphore();
$multirefresh = 1;
}
}
elseif($olddata['stateid'] == 10 && $data['stateid'] == 2) {
if(is_numeric($olddata['vmprofileid'])) {
$vclreloadid = getUserlistID('vclreload@Local');
$imageid = getImageId('noimage');
$revid = getProductionRevisionid($imageid);
$start = getReloadStartTime();
$end = $start + SECINMONTH;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
# move VMs to reload state so vcld will not skip them due to being in maintenance
$query = "UPDATE computer c, "
. "vmhost v "
. "SET c.stateid = 19, "
. "c.notes = '' "
. "WHERE v.computerid = {$data['rscid']} AND "
. "c.vmhostid = v.id";
doQuery($query);
$query = "SELECT vm.id "
. "FROM computer vm, "
. "vmhost v "
. "WHERE v.computerid = {$data['rscid']} AND "
. "vm.vmhostid = v.id";
$qh = doQuery($query);
$fails = array();
while($row = mysql_fetch_assoc($qh)) {
if(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
$enddt, 18, $vclreloadid)) {
$fails[] = $row['id'];
}
else
$multirefresh = 2;
}
if(count($fails)) {
# just directly remove any VMs that failed to be scheduled
$query = "UPDATE computer "
. "SET stateid = 10, "
. "vmhostid = NULL, "
. "notes = '' "
. "WHERE id IN (" . implode(',', $fails) . ")";
doQuery($query);
}
}
}
elseif($olddata['stateid'] == 20 && $data['stateid'] == 20 &&
$olddata['vmprofileid'] != $data['vmprofileid']) {
if($data['provisioning'] != 'none') {
$profiles = getVMProfiles($data['vmprofileid']);
if($profiles[$olddata['vmprofileid']]['imageid'] ==
$profiles[$data['vmprofileid']]['imageid']) {
$query = "UPDATE vmhost "
. "SET vmprofileid = {$data['vmprofileid']} "
. "WHERE computerid = {$data['rscid']} AND "
. "vmprofileid = {$olddata['vmprofileid']}";
doQuery($query);
}
else {
moveReservationsOffVMs($data['rscid']);
cleanSemaphore();
$reloadstart = getCompFinalVMReservationTime($data['rscid'], 1);
if($reloadstart == -1) {
$msg = '';
if(count($updates))
$msg .= "Computer information changes were saved. \nHowever, a ";
else
$msg .= "A ";
$msg .= "problem was encountered while attempting to place assigned ";
$msg .= "VMs into the maintenance state while reloading the computer. ";
$msg .= "Please try again at a later time.\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$promptuserfail = 1;
$title = 'Change VM Host Profile Failed';
}
elseif($reloadstart > 0) {
cleanSemaphore();
$end = date('n/j/y g:i a', $reloadstart);
$msg = '';
if(count($updates))
$msg .= "Computer information changes saved. \nHowever, this ";
else
$msg .= "This ";
$msg .= "computer must be reloaded to change to the selected VM Host ";
$msg .= "Profile and there are VMs on it with reservations until $end. ";
$msg .= "You can:\n";
$msg .= "
Cancel and do nothing
\n";
$msg .= "
Schedule the VMs to be removed and the computer to be ";
$msg .= "reloaded at $end
\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$msg = preg_replace("|$end|", "$end", $msg, 1);
$promptuser = 1;
$cdata = $this->basecdata;
$cdata['reloadstart'] = $reloadstart;
$cdata['imageid'] = $profiles[$data['vmprofileid']]['imageid'];
$cdata['compid'] = $data['rscid'];
$cdata['newstateid'] = $data['stateid'];
$cdata['oldstateid'] = $olddata['stateid'];
$cdata['oldprofileid'] = $olddata['vmprofileid'];
$cdata['vmprofileid'] = $data['vmprofileid'];
$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
$btntxt = 'Schedule Reload';
$title = 'Delayed VM Host Profile Change';
}
else {
# schedule VMs to be removed
$vclreloadid = getUserlistID('vclreload@Local');
$imageid = getImageId('noimage');
$revid = getProductionRevisionid($imageid);
$start = getReloadStartTime();
$end = $start + SECINMONTH;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
$query = "SELECT vm.id "
. "FROM computer vm, "
. "vmhost v "
. "WHERE v.computerid = {$data['rscid']} AND "
. "vm.vmhostid = v.id";
$qh = doQuery($query);
$fails = array();
$cnt = 0;
while($row = mysql_fetch_assoc($qh)) {
$cnt++;
if(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
$enddt, 18, $vclreloadid)) {
$fails[] = $row['id'];
}
}
if(count($fails)) {
# just directly remove any VMs that failed to be scheduled
$query = "UPDATE computer "
. "SET stateid = 10, "
. "vmhostid = NULL, "
. "notes = '' "
. "WHERE id IN (" . implode(',', $fails) . ")";
doQuery($query);
}
cleanSemaphore();
# schedule host to be reloaded
if($cnt)
$start = time() + 120; # allow 2 minutes for VMs to be removed
$rc = $this->scheduleTovmhostinuse($data['rscid'],
$profiles[$data['vmprofileid']]['imageid'],
$start, $data['vmprofileid'],
$olddata['vmprofileid']);
if($rc == 0) {
$msg = '';
if(count($updates))
$msg .= "Computer information changes were saved. \nHowever, a ";
else
$msg .= "A ";
$msg .= "problem was encountered while attempting to reload the ";
$msg .= "computer with the selected VM Host Profile. Please try ";
$msg .= "again at a later time.\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$promptuserfail = 1;
$title = 'VM Host Reload Failed';
}
else
$multirefresh = 3;
}
}
}
else {
$query = "UPDATE vmhost "
. "SET vmprofileid = {$data['vmprofileid']} "
. "WHERE computerid = {$data['rscid']} AND "
. "vmprofileid = {$olddata['vmprofileid']}";
doQuery($query);
}
}
elseif($olddata['stateid'] != 10 && $data['stateid'] == 10) {
moveReservationsOffComputer($data['rscid']);
cleanSemaphore();
$reloadstart = getCompFinalReservationTime($data['rscid']);
if($reloadstart) {
$end = date('n/j/y g:i a', $reloadstart);
$msg = '';
if(count($updates))
$msg .= "Computer information changes saved. \nHowever, this ";
else
$msg .= "This ";
$msg .= "computer has reservations on it until $end. You can:\n";
$msg .= "
Cancel and do nothing
\n";
$msg .= "
Schedule the computer to be moved to maintenance at ";
$msg .= "$end
\n";
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$msg = preg_replace("|$end|", "$end", $msg, 1);
$promptuser = 1;
$cdata = $this->basecdata;
$cdata['reloadstart'] = $reloadstart;
$cdata['imageid'] = getImageId('noimage');
$cdata['compid'] = $data['rscid'];
$cdata['newstateid'] = $data['stateid'];
$cdata['oldstateid'] = $olddata['stateid'];
$promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0);
$btntxt = 'Schedule Maintenance';
$title = 'Delayed Maintenance';
}
# else let UPDATE move it to maintenance
}
# notes (do these at the end because we don't want to update notes if
# state prevented from being changed)
# staying in maintenance
if($olddata['stateid'] == 10 && $data['stateid'] == 10) {
$testnotes = $olddata['notes'];
# check for notes being changed
if(strpos($testnotes, '@') === true) {
$tmp = explode('@', $olddata['notes']);
$testnotes = $tmp[1];
}
if($testnotes != $data['notes']) {
$ts = unixToDatetime(time());
$updates[] = "notes = '{$user['unityid']} $ts@{$data['notes']}'";
}
}
# changing to maintenance
elseif($data['stateid'] == 10) {
$ts = unixToDatetime(time());
$updates[] = "notes = '{$user['unityid']} $ts@{$data['notes']}'";
}
# removing from maintenance
elseif($olddata['stateid'] == 10 && $data['stateid'] != 10) {
$updates[] = "notes = ''";
}
# stateid
if($data['stateid'] != $olddata['stateid'])
$updates[] = "stateid = {$data['stateid']}";
if(count($updates)) {
$query = "UPDATE computer SET "
. implode(', ', $updates)
. " WHERE id = {$data['rscid']}";
doQuery($query);
}
}
# clear user resource cache for this type
$key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 1, 0, 0));
unset($_SESSION['userresources'][$key]);
$key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 0, 0, 0));
unset($_SESSION['userresources'][$key]);
$key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 0, 1, 0, 0));
unset($_SESSION['userresources'][$key]);
$key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 0, 0, 0, 0));
unset($_SESSION['userresources'][$key]);
$args = $this->defaultGetDataArgs;
$arr = array('status' => 'success');
if(is_array($data['rscid'])) {
$tmp = $this->getData($args);
$arr['addmode'] = 'multiple';
$arr['data'] = array();
foreach($data['rscid'] as $compid) {
$tmp[$compid]['name'] = $tmp[$compid]['hostname'];
$arr['data'][] = $tmp[$compid];
}
$arr['grouphelp'] = "Select groups from the list on the right and click the "
. "Add button to add the new computer set to those groups.
";
$cdata = $this->basecdata;
$cdata['newids'] = $data['rscid'];
$cdata['mode'] = 'add';
$arr['addcont'] = addContinuationsEntry('AJaddRemGroupResource', $cdata);
$cdata['mode'] = 'remove';
$arr['remcont'] = addContinuationsEntry('AJaddRemGroupResource', $cdata);
}
else {
if($add)
$arr['addmode'] = 'single';
$args['rscid'] = $data['rscid'];
$tmp = $this->getData($args);
$data = $tmp[$data['rscid']];
$arr['data'] = $data;
$arr['data']['name'] = $arr['data']['hostname'];
}
if($add) {
$arr['action'] = 'add';
$arr['nogroups'] = 0;
$groups = getUserResources(array($this->restype . 'Admin'), array('manageGroup'), 1);
if(count($groups[$this->restype]))
$arr['groupingHTML'] = $this->groupByResourceHTML();
else
$arr['nogroups'] = 1;
}
else
$arr['action'] = 'edit';
if($promptuser) {
$arr['promptuser'] = 1;
$arr['btntxt'] = $btntxt;
$arr['title'] = $title;
$arr['msg'] = $msg;
$arr['cont'] = $promptcont;
}
elseif($promptuserfail) {
$arr['promptuserfail'] = 1;
$arr['title'] = $title;
$arr['msg'] = $msg;
}
if($multirefresh)
$arr['multirefresh'] = $multirefresh;
sendJSON($arr);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn validateResourceData()
///
/// \return array with these fields:\n
/// \b rscid - id of resource (from computer table)\n
/// \b name - hostname of computer\n
/// \b startnum - start number when doing multiple add\n
/// \b endnum - end number when doing multiple add\n
/// \b owner\n
/// \b type - type of computer\n
/// \b IPaddress - public IP address\n
/// \b privateIPaddress - private IP address\n
/// \b eth0macaddress - public MAC address\n
/// \b eth1macaddress - private MAC address\n
/// \b startpubipaddress - start public IP address when doing multiple add\n
/// \b endpubipaddress - end public IP address when doing multiple add\n
/// \b startprivipaddress - start private IP address when doing multiple
/// add\n
/// \b endprivipaddress - end private IP address when doing multiple add\n
/// \b startmac - start MAC address when doing multiple add\n
/// \b provisioningid - id of provisioning engine for computer(s)\n
/// \b stateid - id for state of computer\n
/// \b notes - maintenance notes when setting computer to maintenance state\n
/// \b vmprofileid - id of vmprofile when setting to vmhostinuse state\n
/// \b platformid - id of platform\n
/// \b scheduleid - id of schedule\n
/// \b ram\n
/// \b cores\n
/// \b procspeed\n
/// \b network\n
/// \b predictivemoduleid - id of module to use when preloading nodes\n
/// \b natenabled - 1 to use NAT for this computer, 0 not to\n
/// \b nathostid - id of NAT host for this computer\n
/// \b location - free string describing location\n
/// \b mode - 'edit' or 'add'\n
/// \b addmode - 'single' or 'multiple'\n
/// \b startpubiplong - numeric value for start public IP address when doing
/// multiple add\n
/// \b endpubiplong - numeric value for end public IP address when doing
/// multiple add\n
/// \b startpriviplong - numeric value for start private IP address when
/// doing multiple add\n
/// \b endpriviplong - numeric value for end private IP address when doing
/// multiple add\n
/// \b error - 0 if submitted data validates; 1 if anything is invalid\n
/// \b errormsg - if error = 1; string of error messages separated by html
/// break tags
///
/// \brief validates form input from editing or adding a computer
///
/////////////////////////////////////////////////////////////////////////////
function validateResourceData() {
global $user;
$return = array('error' => 0);
$return['rscid'] = getContinuationVar('rscid', 0);
$return['name'] = processInputVar('name', ARG_STRING);
$return['startnum'] = processInputVar('startnum', ARG_NUMERIC);
$return['endnum'] = processInputVar('endnum', ARG_NUMERIC);
$return['owner'] = processInputVar('owner', ARG_STRING, "{$user['unityid']}@{$user['affiliation']}");
$return['type'] = processInputVar('type', ARG_STRING);
$return['IPaddress'] = processInputVar('ipaddress', ARG_STRING);
$return['privateIPaddress'] = processInputVar('privateipaddress', ARG_STRING);
$return['eth0macaddress'] = processInputVar('privatemac', ARG_STRING);
$return['eth1macaddress'] = processInputVar('publicmac', ARG_STRING);
$return['startpubipaddress'] = processInputVar('startpubipaddress', ARG_STRING);
$return['endpubipaddress'] = processInputVar('endpubipaddress', ARG_STRING);
$return['startprivipaddress'] = processInputVar('startprivipaddress', ARG_STRING);
$return['endprivipaddress'] = processInputVar('endprivipaddress', ARG_STRING);
$return['startmac'] = processInputVar('startmac', ARG_STRING);
$return['provisioningid'] = processInputVar('provisioningid', ARG_NUMERIC);
$return['stateid'] = processInputVar('stateid', ARG_NUMERIC);
$return['notes'] = processInputVar('notes', ARG_STRING);
$return['vmprofileid'] = processInputVar('vmprofileid', ARG_NUMERIC);
$return['platformid'] = processInputVar('platformid', ARG_NUMERIC);
$return['scheduleid'] = processInputVar('scheduleid', ARG_NUMERIC);
$return['ram'] = processInputVar('ram', ARG_NUMERIC);
$return['cores'] = processInputVar('cores', ARG_NUMERIC);
$return['procspeed'] = processInputVar('procspeed', ARG_NUMERIC);
$return['network'] = processInputVar('network', ARG_NUMERIC);
$return['predictivemoduleid'] = processInputVar('predictivemoduleid', ARG_NUMERIC);
$return['natenabled'] = processInputVar('natenabled', ARG_NUMERIC);
$return['nathostid'] = processInputVar('nathostid', ARG_NUMERIC);
$return['nathostenabled'] = processInputVar('nathostenabled', ARG_NUMERIC);
$return['natpublicIPaddress'] = processInputVar('natpublicipaddress', ARG_STRING);
$return['natinternalIPaddress'] = processInputVar('natinternalipaddress', ARG_STRING);
$return['location'] = processInputVar('location', ARG_STRING);
$addmode = processInputVar('addmode', ARG_STRING);
if(! is_null($addmode) && $addmode != 'single' && $addmode != 'multiple') {
$return['error'] = 1;
$return['errormsg'] = "Invalid Add mode submitted";
return $return;
}
$olddata = getContinuationVar('olddata');
if($return['rscid'] == 0)
$return['mode'] = 'add';
else
$return['mode'] = 'edit';
$errormsg = array();
# hostname
$hostreg = '/^[a-zA-Z0-9_][-a-zA-Z0-9_\.]{1,49}$/';
if($return['mode'] == 'add' && $addmode == 'multiple')
$hostreg = '/^[a-zA-Z0-9_%][-a-zA-Z0-9_\.%]{1,49}$/';
if(! preg_match($hostreg, $return['name'])) {
$return['error'] = 1;
$errormsg[] = "Hostname can only contain letters, numbers, dashes(-), periods(.), and underscores(_). It can be from 1 to 50 characters long";
}
elseif($this->checkForHostname($return['name'], $return['rscid'])) {
$return['error'] = 1;
$errormsg[] = "A computer already exists with this hostname.";
}
# add multiple
if($return['mode'] == 'add' && $addmode == 'multiple') {
# startnum/endnum
if($return['startnum'] < 0 || $return['startnum'] > 255) {
$return['error'] = 1;
$errormsg[] = "Start must be from 0 to 255";
}
if($return['endnum'] < 0 || $return['endnum'] > 255) {
$return['error'] = 1;
$errormsg[] = "End must be from 0 to 255";
}
if($return['startnum'] >= 0 && $return['startnum'] <= 255 &&
$return['endnum'] >= 0 && $return['endnum'] <= 255 &&
$return['startnum'] > $return['endnum']) {
$return['error'] = 1;
$errormsg[] = "Start must be >= End";
}
$checkhosts = array();
for($i = $return['startnum']; $i <= $return['endnum']; $i++)
$checkhosts[] = str_replace('%', $i, $return['name']);
$allhosts = implode("','", $checkhosts);
$query = "SELECT hostname FROM computer "
. "WHERE hostname IN ('$allhosts') AND "
. "deleted = 0";
$qh = doQuery($query);
$exists = array();
while($row = mysql_fetch_assoc($qh))
$exists[] = $row['hostname'];
if(count($exists)) {
$hosts = implode(', ', $exists);
$return['error'] = 1;
$errormsg[] = "There are already computers with these hostnames: $hosts";
}
}
else {
$return['startnum'] = 0;
$return['endnum'] = 0;
}
# owner
if(! validateUserid($return['owner'])) {
$return['error'] = 1;
$errormsg[] = "Submitted owner is not valid";
}
# type
if(! preg_match('/^(blade|lab|virtualmachine)$/', $return['type'])) {
$return['error'] = 1;
$errormsg[] = "Submitted type is not valid";
}
# edit or add single
if($return['rscid'] || ($return['mode'] == 'add' && $addmode == 'single')) {
# ipaddress
if(! validateIPv4addr($return['IPaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid Public IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
}
# private ipaddress
if(strlen($return['privateIPaddress']) &&
! validateIPv4addr($return['privateIPaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid Private IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
}
# eth0macaddress
if(strlen($return['eth0macaddress'])) {
if(! preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $return["eth0macaddress"])) {
$return['error'] = 1;
$errormsg[] = "Invalid Private MAC address. Must be XX:XX:XX:XX:XX:XX "
. "with each pair of XX being from 00 to FF (inclusive)";
}
elseif($this->checkForMACaddress($return['eth0macaddress'], 0, $return['rscid'])) {
$return['error'] = 1;
$errormsg[] = "There is already a computer with this Private MAC address.";
}
}
# eth1macaddress
if(strlen($return['eth1macaddress'])) {
if(! preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $return["eth1macaddress"])) {
$return['error'] = 1;
$errormsg[] = "Invalid Public MAC address. Must be XX:XX:XX:XX:XX:XX "
. "with each pair of XX being from 00 to FF (inclusive)";
}
elseif($this->checkForMACaddress($return['eth1macaddress'], 1, $return['rscid'])) {
$return['error'] = 1;
$errormsg[] = "There is already a computer with this Public MAC address.";
}
}
}
else {
$return['IPaddress'] = '';
$return['privateIPaddress'] = '';
$return['eth0macaddress'] = '';
$return['eth1macaddress'] = '';
}
# add multiple
if($return['mode'] == 'add' && $addmode == 'multiple') {
if(! validateIPv4addr($return['startpubipaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid Start Public IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
}
if(! validateIPv4addr($return['endpubipaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid End Public IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
}
if(! validateIPv4addr($return['startprivipaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid Start Private IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
}
if(! validateIPv4addr($return['endprivipaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid End Private IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
}
$startpubiplong = ip2long($return['startpubipaddress']);
$endpubiplong = ip2long($return['endpubipaddress']);
if($startpubiplong > $endpubiplong) {
$return['error'] = 1;
$errormsg[] = "Start Public IP Address must be lower or equal to End Public IP Address";
}
elseif(($endpubiplong - $startpubiplong) != ($return['endnum'] - $return['startnum'])) {
$return['error'] = 1;
$errormsg[] = "Public IP Address range does not equal Start/End range";
}
$startpriviplong = ip2long($return['startprivipaddress']);
$endpriviplong = ip2long($return['endprivipaddress']);
if($startpriviplong > $endpriviplong) {
$return['error'] = 1;
$errormsg[] = "Start Private IP Address must be lower or equal to End Private IP Address";
}
elseif(($endpriviplong - $startpriviplong) != ($return['endnum'] - $return['startnum'])) {
$return['error'] = 1;
$errormsg[] = "Private IP Address range does not equal Start/End range";
}
$return['startpubiplong'] = $startpubiplong;
$return['endpubiplong'] = $endpubiplong;
$return['startpriviplong'] = $startpriviplong;
$return['endpriviplong'] = $endpriviplong;
$cnt = $endpubiplong - $startpubiplong + 1;
if($return['startmac'] != '') {
if(! preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $return['startmac'])) {
$return['error'] = 1;
$errormsg[] = "Invalid Start MAC address. Must be XX:XX:XX:XX:XX:XX "
. "with each pair of XX being from 00 to FF (inclusive)";
}
elseif($this->checkMultiAddMacs($return['startmac'], $cnt, $msg, $macs)) {
$return['error'] = 1;
$errormsg[] = $msg;
}
$return['macs'] = $macs;
}
else
$return['macs'] = array();
}
else {
$return['startpubipaddress'] = '';
$return['endpubipaddress'] = '';
$return['startprivipaddress'] = '';
$return['endprivipaddress'] = '';
$return['startmac'] = '';
}
# provisioningid
$provisioning = getProvisioning();
if(! array_key_exists($return['provisioningid'], $provisioning)) {
$return['error'] = 1;
$errormsg[] = "Invalid Provisioning Engine selected";
}
else
$return['provisioning'] = $provisioning[$return['provisioningid']]['name'];
# stateid 2 - available, 10 - maintenance, 20 - vmhostinuse
if(! preg_match('/^(2|10|20)$/', $return['stateid']) &&
($return['mode'] == 'add' || $return['stateid'] != $olddata['stateid'])) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for State";
}
# validate type/provisioning combinations
$provtypes = getProvisioningTypes();
if(($return['mode'] == 'add' || $olddata['provisioningid'] != $return['provisioningid']) &&
! array_key_exists($return['provisioningid'], $provtypes[$return['type']])) {
$return['error'] = 1;
$errormsg[] = "Invalid Provisioning Engine selected for computer type";
}
# validate type/provisioning/state combinations
if($return['mode'] == 'add' || $olddata['stateid'] != $return['stateid']) {
if($return['type'] == 'lab') {
if($return['stateid'] != 2 && $return['stateid'] != 10) {
$return['error'] = 1;
$errormsg[] = "Invalid state submitted for computer type Lab";
}
}
elseif($return['type'] == 'virtualmachine') {
if($return['stateid'] != 10 &&
($return['mode'] == 'add' || ! is_numeric($olddata['vmhostid']) || $return['stateid'] != 2)) {
$return['error'] = 1;
$errormsg[] = "Invalid state submitted for computer type Virtual Machine";
}
}
elseif($return['type'] == 'blade') {
if($provisioning[$return['provisioningid']]['name'] == 'none' &&
$return['stateid'] != 10 && $return['stateid'] != 20) {
$return['error'] = 1;
$errormsg[] = "Invalid state submitted for computer type Bare Metal";
}
}
}
# notes
if($return['stateid'] == 10) {
if(! preg_match('/^([-a-zA-Z0-9_\. ,#\(\)=\+:;]{0,5000})$/', $return['notes'])) {
$return['error'] = 1;
$errormsg[] = "Maintenance reason can be up to 5000 characters long and may only contain letters, numbers, spaces and these characters: - , . _ # ( ) = + : ;";
}
}
else
$return['notes'] = '';
# vmprofileid
$profiles = getVMProfiles();
if($return['type'] == 'blade' && $return['stateid'] == 20 &&
! array_key_exists($return['vmprofileid'], $profiles)) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for VM Host Profile";
}
# platformid
$platforms = getPlatforms();
if(! array_key_exists($return['platformid'], $platforms)) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for Platform";
}
# scheduleid
$schedules = getSchedules();
if(! array_key_exists($return['scheduleid'], $schedules)) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for Schedule";
}
# ram
if($return['ram'] < 500 || $return['ram'] > 16777215) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for RAM";
}
# cores
if($return['cores'] < 1 || $return['cores'] > 255) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for No. Cores";
}
# procspeed
if($return['procspeed'] < 500 || $return['procspeed'] > 10000) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for Processor Speed";
}
# network
if(! preg_match('/^(10|100|1000|10000|100000)$/', $return['network'])) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for Network";
}
# predictivemoduleid
$premodules = getPredictiveModules();
if(! array_key_exists($return['predictivemoduleid'], $premodules)) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for Predictive Loading Module";
}
$naterror = 0;
# natenabled
if($return['natenabled'] != 0 && $return['natenabled'] != 1) {
$return['error'] = 1;
$errormsg[] = "Invalid value for Connect Using NAT";
$naterror = 1;
}
# nathostid
$nathosts = getNAThosts();
if(($return['natenabled'] && $return['nathostid'] == 0) ||
($return['nathostid'] != 0 && ! array_key_exists($return['nathostid'], $nathosts))) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for NAT Host";
$naterror = 1;
}
# nat change - check for active reservations
$vclreloadid = getUserlistID('vclreload@Local');
if($return['mode'] == 'edit') {
if($olddata['nathostid'] == '')
$olddata['nathostid'] = 0;
if(! $naterror && ($olddata['natenabled'] != $return['natenabled'] ||
$olddata['nathostid'] != $return['nathostid'])) {
$query = "SELECT rq.id "
. "FROM request rq, "
. "reservation rs "
. "WHERE rs.requestid = rq.id AND "
. "rs.computerid = {$return['rscid']} AND "
. "rq.start <= NOW() AND "
. "rq.end > NOW() AND "
. "rq.stateid NOT IN (1,5,11,12) AND "
. "rq.laststateid NOT IN (1,5,11,12) AND "
. "rq.userid != $vclreloadid";
$qh = doQuery($query);
if(mysql_num_rows($qh)) {
$return['error'] = 1;
$errormsg[] = "This computer has an active reservation. NAT settings cannot be changed for computers having active reservations.";
}
}
}
$nathosterror = 0;
# nathostenabled
if($return['nathostenabled'] != 0 && $return['nathostenabled'] != 1) {
$return['error'] = 1;
$errormsg[] = "Invalid value for Use as NAT Host";
$nathosterror = 1;
}
# natpublicIPaddress
if($return['nathostenabled'] &&
($return['mode'] == 'edit' || $addmode == 'single')) {
if(! validateIPv4addr($return['natpublicIPaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid NAT Public IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
$nathosterror = 1;
}
# natinternalIPaddress
if(! validateIPv4addr($return['natinternalIPaddress'])) {
$return['error'] = 1;
$errormsg[] = "Invalid NAT Internal IP address. Must be w.x.y.z with each of "
. "w, x, y, and z being between 1 and 255 (inclusive)";
$nathosterror = 1;
}
}
# nat host change - check for active reservations
if(! $nathosterror && $return['mode'] == 'edit') {
if($olddata['nathostenabled'] != $return['nathostenabled'] ||
$olddata['natpublicIPaddress'] != $return['natpublicIPaddress'] ||
$olddata['natinternalIPaddress'] != $return['natinternalIPaddress']) {
$query = "SELECT rq.id "
. "FROM request rq, "
. "reservation rs, "
. "nathostcomputermap nhcm, "
. "nathost nh "
. "WHERE rs.requestid = rq.id AND "
. "rs.computerid = nhcm.computerid AND "
. "nhcm.nathostid = nh.id AND "
. "nh.resourceid = {$olddata['resourceid']} AND "
. "rq.start <= NOW() AND "
. "rq.end > NOW() AND "
. "rq.stateid NOT IN (1,5,11,12) AND "
. "rq.laststateid NOT IN (1,5,11,12) AND "
. "rq.userid != $vclreloadid";
$qh = doQuery($query);
if(mysql_num_rows($qh)) {
$return['error'] = 1;
$errormsg[] = "This computer is the NAT host for other computers that have active reservations. NAT host settings cannot be changed while providing NAT for active reservations.";
}
}
}
# location
if(! preg_match('/^([-a-zA-Z0-9_\. ,@#\(\)]{0,255})$/', $return['location'])) {
$return['error'] = 1;
$errormsg[] = "Invalid value submitted for Location";
}
if($return['mode'] == 'add')
$return['addmode'] = $addmode;
if($return['error'])
$return['errormsg'] = implode(' ', $errormsg);
return $return;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn checkForHostname($hostname, $compid)
///
/// \param $hostname - a computer hostname
/// \param $compid - (optional) a computer id to ignore
///
/// \return 1 if $hostname is already in the computer table, 0 if not
///
/// \brief checks for $hostname being somewhere in the computer table except
/// for $compid
///
/////////////////////////////////////////////////////////////////////////////
function checkForHostname($hostname, $compid='') {
$query = "SELECT id FROM computer "
. "WHERE hostname = '$hostname' AND "
. "deleted = 0";
if(! empty($compid))
$query .= " AND id != $compid";
$qh = doQuery($query);
if(mysql_num_rows($qh))
return 1;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn checkForMACaddress($mac, $num, $compid)
///
/// \param $mac - computer mac address
/// \param $num - which mac address to check - 0 or 1
/// \param $compid - (optional) a computer id to ignore
///
/// \return 1 if $mac/$num is already in the computer table, 0 if not
///
/// \brief checks for $mac being somewhere in the computer table except
/// for $compid
///
/////////////////////////////////////////////////////////////////////////////
function checkForMACaddress($mac, $num, $compid='') {
if($num == 0)
$field = 'eth0macaddress';
else
$field = 'eth1macaddress';
$query = "SELECT id FROM computer "
. "WHERE $field = '$mac' AND "
. "deleted = 0";
if(! empty($compid))
$query .= " AND id != $compid";
$qh = doQuery($query);
if(mysql_num_rows($qh))
return 1;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn checkForIPaddress($ipaddress, $type, $compid)
///
/// \param $ipaddress - a computer ip address
/// \param $type - 'public' or 'private' - which IP address to check
/// \param $compid - (optional) a computer id to ignore
///
/// \return 1 if $ipaddress is already in the computer table, 0 if not
///
/// \brief checks for $ipaddress being somewhere in the computer table except
/// for $compid
///
/////////////////////////////////////////////////////////////////////////////
function checkForIPaddress($ipaddress, $type, $compid='') {
if($type == 'public')
$field = 'IPaddress';
else
$field = 'privateIPaddress';
$query = "SELECT id FROM computer "
. "WHERE $field = '$ipaddress'";
if(! empty($compid))
$query .= " AND id != $compid";
$qh = doQuery($query);
if(mysql_num_rows($qh))
return 1;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn addResource($data)
///
/// \param $data - array of needed data for adding a new resource
///
/// \return id of new resource
///
/// \brief handles adding a new computer and other associated data to the
/// database
///
/////////////////////////////////////////////////////////////////////////////
function addResource($data) {
global $user;
$ownerid = getUserlistID($data['owner']);
$noimageid = getImageId('noimage');
$norevid = getProductionRevisionid($noimageid);
$keys = array('hostname', 'ownerid',
'type', 'IPaddress',
'privateIPaddress', 'eth0macaddress',
'eth1macaddress', 'provisioningid',
'stateid', 'platformid',
'scheduleid', 'RAM',
'procnumber', 'procspeed',
'network', 'currentimageid',
'imagerevisionid', 'location',
'predictivemoduleid');
if($data['addmode'] == 'single') {
$eth0 = "'{$data['eth0macaddress']}'";
if($data['eth0macaddress'] == '')
$eth0 = 'NULL';
$eth1 = "'{$data['eth1macaddress']}'";
if($data['eth1macaddress'] == '')
$eth1 = 'NULL';
$values = array("'{$data['name']}'", $ownerid,
"'{$data['type']}'", "'{$data['IPaddress']}'",
"'{$data['privateIPaddress']}'", $eth0,
$eth1, $data['provisioningid'],
$data['stateid'], $data['platformid'],
$data['scheduleid'], $data['ram'],
$data['cores'], $data['procspeed'],
$data['network'], $noimageid,
$norevid, "'{$data['location']}'",
$data['predictivemoduleid']);
$query = "INSERT INTO computer ("
. implode(', ', $keys) . ") VALUES ("
. implode(', ', $values) . ")";
doQuery($query);
$rscid = dbLastInsertID();
# vmhost entry
if($data['stateid'] == '20') {
$query = "INSERT INTO vmhost "
. "(computerid, "
. "vmlimit, "
. "vmprofileid) "
. "VALUES ($rscid, "
. "5, "
. "{$data['vmprofileid']})";
doQuery($query);
}
# NAT
if($data['natenabled']) {
$query = "INSERT INTO nathostcomputermap "
. "(computerid, "
. "nathostid) "
. "VALUES ($rscid, "
. "{$data['nathostid']})";
doQuery($query);
}
// add entry in resource table
$query = "INSERT INTO resource "
. "(resourcetypeid, "
. "subid) "
. "VALUES (12, "
. "$rscid)";
doQuery($query);
$resourceid = dbLastInsertID();
# NAT host
if($data['nathostenabled']) {
$query = "INSERT INTO nathost "
. "(resourceid, "
. "publicIPaddress, "
. "internalIPaddress) "
. "VALUES "
. "($resourceid, "
. "'{$data['natpublicIPaddress']}', "
. "'{$data['natinternalIPaddress']}')";
doQuery($query);
}
return $rscid;
}
else {
# add multiple computers
$alldis = array();
for($i = $data['startnum'], $cnt = 0; $i <= $data['endnum']; $i++, $cnt++) {
$hostname = str_replace('%', $i, $data["name"]);
$pubip = long2ip($data['startpubiplong'] + $cnt);
$privip = long2ip($data['startpriviplong'] + $cnt);
if(count($data['macs'])) {
$eth0 = "'" . $data['macs'][$cnt * 2] . "'";
$eth1 = "'" . $data['macs'][($cnt * 2) + 1] . "'";
}
else {
$eth0 = 'NULL';
$eth1 = 'NULL';
}
$values = array("'$hostname'", $ownerid,
"'{$data['type']}'", "'$pubip'",
"'$privip'", $eth0,
$eth1, $data['provisioningid'],
$data['stateid'], $data['platformid'],
$data['scheduleid'], $data['ram'],
$data['cores'], $data['procspeed'],
$data['network'], $noimageid,
$norevid, "'{$data['location']}'",
$data['predictivemoduleid']);
$query = "INSERT INTO computer ("
. implode(', ', $keys) . ") VALUES ("
. implode(', ', $values) . ")";
doQuery($query);
$rscid = dbLastInsertID();
# vmhost entry
if($data['stateid'] == '20') {
$query = "INSERT INTO vmhost "
. "(computerid, "
. "vmlimit, "
. "vmprofileid) "
. "VALUES ($rscid, "
. "5, "
. "{$data['vmprofileid']})";
doQuery($query);
}
# NAT
if($data['natenabled']) {
$query = "INSERT INTO nathostcomputermap "
. "(computerid, "
. "nathostid) "
. "VALUES ($rscid, "
. "{$data['nathostid']})";
doQuery($query);
}
// add entry in resource table
$query = "INSERT INTO resource "
. "(resourcetypeid, "
. "subid) "
. "VALUES (12, "
. "$rscid)";
doQuery($query);
$allids[] = $rscid;
}
return $allids;
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// \fn AJcanceltovmhostinuse()
///
/// \brief cancels any reservations to place the computer in the vmhostinuse
/// state
///
////////////////////////////////////////////////////////////////////////////////
function AJcanceltovmhostinuse() {
global $mysql_link_vcl;
$compid = getContinuationVar('compid');
$type = 'none';
$query = "DELETE FROM request "
. "WHERE start > NOW() AND "
. "stateid = 21 AND "
. "id IN (SELECT requestid "
. "FROM reservation "
. "WHERE computerid = $compid)";
doQuery($query);
if(mysql_affected_rows($mysql_link_vcl))
$type = 'future';
$query = "UPDATE request rq, "
. "reservation rs, "
. "state ls "
. "SET rq.stateid = 1 "
. "WHERE rs.requestid = rq.id AND "
. "rs.computerid = $compid AND "
. "rq.start <= NOW() AND "
. "rq.laststateid = ls.id AND "
. "ls.name = 'tovmhostinuse'";
doQuery($query);
if(mysql_affected_rows($mysql_link_vcl))
$type = 'current';
$query = "SELECT rq.start "
. "FROM request rq, "
. "reservation rs, "
. "state ls, "
. "state cs "
. "WHERE rs.requestid = rq.id AND "
. "rs.computerid = $compid AND "
. "rq.laststateid = ls.id AND "
. "rq.stateid = cs.id AND "
. "ls.name = 'tovmhostinuse' AND "
. "cs.name NOT IN ('failed', 'maintenance', 'complete', 'deleted') AND "
. "rq.end > NOW() "
. "ORDER BY rq.start";
$qh = doQuery($query);
if(mysql_num_rows($qh))
$arr = array('status' => 'failed');
else {
if($type == 'now')
$msg = "The reservation currently being processed to place this "
. "computer in the vmhostinuse state has been flagged for "
. "deletion. As soon as the deletion can be processed, the "
. "computer will be set to the available state.";
else
$msg = "The reservation scheduled to place this computer in the "
. "vmhostinuse state has been deleted.";
$arr = array('status' => 'success', 'msg' => $msg);
}
sendJSON($arr);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn scheduleTovmhostinuse($compid, $imageid, $start, $vmprofileid,
/// $oldvmprofileid)
///
/// \param $compid - id of a computer
/// \param $imageid - id of an image
/// \param $start - start time in unix timestamp format
/// \param $vmprofileid - id of vmprofile
/// \param $oldvmprofileid - id of possible previous vmprofile
///
/// \return 0 on failure, 1 on success
///
/// \brief schedules or updates a reservation to move a host to the
/// vmhostinuse state
///
/////////////////////////////////////////////////////////////////////////////
function scheduleTovmhostinuse($compid, $imageid, $start, $vmprofileid,
$oldvmprofileid) {
# create a reload reservation to load machine with image
# corresponding to selected vm profile
$vclreloadid = getUserlistID('vclreload@Local');
$revid = getProductionRevisionid($imageid);
$end = $start + SECINYEAR; # don't want anyone making a future reservation for this machine
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
$failed = 0;
$mnid = findManagementNode($compid, $startdt, 'now');
if($mnid == 0)
return 0;
# check for existing tovmhostinuse reservation
$query = "SELECT rq.id, "
. "rq.start, "
. "rq.end, "
. "rs.imageid "
. "FROM request rq, "
. "reservation rs "
. "WHERE rs.requestid = rq.id AND "
. "rs.computerid = $compid AND "
. "rq.stateid = 21 AND "
. "rq.start > NOW() "
. "ORDER BY rq.start "
. "LIMIT 1";
$qh = doQuery($query);
if($row = mysql_fetch_assoc($qh)) {
if(! retryGetSemaphore($imageid, $revid, $mnid, $compid, $startdt, $enddt, $row['id']))
return 0;
# update existing reservation
$updates = array();
$startts = datetimeToUnix($row['start']);
if($start < $startts)
$updates[] = "rq.start = '$startdt'";
elseif($start > $startts)
$this->startchange = $startts;
if($row['imageid'] != $imageid)
$updates[] = "rs.imageid = $imageid";
if(count($updates)) {
$query = "UPDATE request rq, "
. "reservation rs "
. "SET " . implode(',', $updates)
." WHERE rs.requestid = rq.id AND "
. "rq.id = {$row['id']}";
doQuery($query);
}
}
else {
if(! retryGetSemaphore($imageid, $revid, $mnid, $compid, $startdt, $enddt))
return 0;
# add new reservation
if(! (simpleAddRequest($compid, $imageid, $revid, $startdt, $enddt, 21,
$vclreloadid)))
return 0;
}
cleanSemaphore();
$this->updateVmhostProfile($compid, $vmprofileid, $oldvmprofileid);
return 1;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn updateVmhostProfile($compid, $newprofileid, $oldprofileid)
///
/// \param $compid - id of computer
/// \param $newprofileid - id of new vmprofile
/// \param $oldprofileid - id of possible previous vmprofile
///
/// \brief updates a vmhost entry's vmprofileid or creates a new vmhost entry
///
/////////////////////////////////////////////////////////////////////////////
function updateVmhostProfile($compid, $newprofileid, $oldprofileid) {
if(is_numeric($oldprofileid)) {
if($oldprofileid != $newprofileid) {
# update existing entry
$query = "UPDATE vmhost "
. "SET vmprofileid = $newprofileid "
. "WHERE computerid = $compid AND "
. "vmprofileid = $oldprofileid";
doQuery($query);
}
}
else {
# create vmhost entry
$query = "INSERT INTO vmhost "
. "(computerid, "
. "vmlimit, "
. "vmprofileid) "
. "VALUES ($compid, "
. "5, "
. "$newprofileid)";
doQuery($query);
}
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJsubmitComputerStateLater()
///
/// \brief schedules a computer to be converted to another state at a future
/// time
///
/////////////////////////////////////////////////////////////////////////////
function AJsubmitComputerStateLater() {
$compid = getContinuationVar('compid');
$maintenanceonly = getContinuationVar('maintenanceonly', 0);
$start = getContinuationVar('reloadstart');
$end = $start + SECINYEAR;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
$vmprofileid = getContinuationVar('vmprofileid', 0);
$oldprofileid = getContinuationVar('oldprofileid', 0);
$newstateid = getContinuationVar('newstateid', 0);
$oldstateid = getContinuationVar('oldstateid', 0);
$imageid = getContinuationVar('imageid');
$revid = getProductionRevisionid($imageid);
$mode = processInputVar('mode', ARG_STRING);
$msg = '';
$refreshcount = 0;
if($oldstateid == 10 && $newstateid == 20 &&
! is_null($mode) && $mode != 'direct' && $mode != 'reload') {
$errmsg = "Invalid information submitted";
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
$delayed = 0;
# maintenance directly back to vmhostinuse
if($mode == 'direct') {
$vmids = getContinuationVar('vmids');
if(count($vmids)) {
$allids = implode(',', $vmids);
$query = "UPDATE computer "
. "SET stateid = 2, "
. "notes = '' "
. "WHERE id in ($allids)";
doQuery($query);
}
$query = "UPDATE computer "
. "SET stateid = 20, "
. "notes = '' "
. "WHERE id = $compid";
doQuery($query);
$msg .= "The computer has been moved back to the vmhostinuse state and ";
$msg .= "the appropriate VMs have been moved to the available state.";
$title = "Change to vmhostinuse";
$refreshcount = 1;
}
# maintenance back to vmhostinuse with a reload
elseif($mode == 'reload') {
$vmids = getContinuationVar('vmids');
if(count($vmids))
$this->scheduleVMsToAvailable($vmids);
$start = getReloadStartTime();
$rc = $this->scheduleTovmhostinuse($compid, $imageid, $start,
$vmprofileid, $oldprofileid);
if($rc == 0) {
$errmsg .= "A problem was encountered while attempting to reload the ";
$errmsg .= "computer with the selected VM Host Profile. Please try ";
$errmsg .= "again at a later time.\n";
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
$msg .= "The computer has been scheduled to go back to the vmhostinuse ";
$msg .= "state and the appropriate VMs have been scheduled to go back ";
$msg .= "to the available state at %s.";
$title = "Change to vmhostinuse";
}
# anything else to vmhostinuse
elseif($oldstateid != 20 && $newstateid == 20) {
moveReservationsOffComputer($compid);
cleanSemaphore();
$mnid = findManagementNode($compid, unixToDatetime($start), 'future');
$tmp = getCompFinalReservationTime($compid, 21);
$checkstart = getExistingChangeStateStartTime($compid, 21);
if(! $checkstart && $checkstart != $start && $tmp > $start) {
$delayed = 1;
$start = $tmp;
$end = $start + SECINYEAR;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
}
$vclreloadid = getUserlistID('vclreload@Local');
if($maintenanceonly) {
if(! retryGetSemaphore($imageid, $revid, $mnid, $compid, $start, $end)) {
$errmsg = "An error was encountered while trying to schedule this \n";
$errmsg .= "computer for the maintenance state. Please try again later.\n";
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
# create a tomaintenance reservation
if(! (simpleAddRequest($compid, $imageid, $revid, $startdt, $enddt,
18, $vclreloadid))) {
$errmsg = "An error was encountered while trying to schedule this \n";
$errmsg .= "computer for the maintenance state. Please try again later.\n";
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
cleanSemaphore();
return;
}
$msg .= "The computer has been scheduled to be moved to the ";
$msg .= "maintenance state at %s.";
$title = "Change to maintenance state";
}
else {
# create a reload reservation to load machine with image
# corresponding to selected vm profile
$rc = $this->scheduleTovmhostinuse($compid, $imageid, $start,
$vmprofileid, $oldprofileid);
if(isset($this->startchange)) {
$start = $this->startchange;
$delayed = 1;
}
if($rc == 0) {
$errmsg = "An error was encountered while trying to convert this ";
$errmsg .= "computer to a VM host server. Please try again later.";
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
$msg .= "The computer has been scheduled to be moved to the ";
$msg .= "vmhostinuse state at %s.";
$title = "Change to vmhostinuse state";
}
cleanSemaphore();
}
# vmhostinuse to available
elseif($oldstateid == 20 && $newstateid == 2) {
$tmp = getCompFinalVMReservationTime($compid, 1);
if($tmp == -1) {
$errmsg .= "A problem was encountered while attempting to schedule ";
$errmsg .= "assigned VMs to be removed from the computer. Please ";
$errmsg .= "try again at a later time.\n";
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
elseif($tmp > $start) {
$delayed = 1;
$start = $tmp;
$end = $start + SECINYEAR;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
}
$vclreloadid = getUserlistID('vclreload@Local');
$query = "SELECT vm.id "
. "FROM computer vm, "
. "vmhost v "
. "WHERE v.computerid = $compid AND "
. "vm.vmhostid = v.id";
$qh = doQuery($query);
$fail = 0;
while($row = mysql_fetch_assoc($qh)) {
if(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
$enddt, 18, $vclreloadid)) {
$fail = 1;
break;
}
}
cleanSemaphore();
if($fail) {
$errmsg = "A problem was encountered while attempting to remove VMs ";
$errmsg .= "from the computer. Please try again at a later time.\n";
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
else {
$start = $start + 300;
$end = $start + SECINYEAR;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
if(! simpleAddRequest($compid, $imageid, $revid, $startdt,
$enddt, 19, $vclreloadid)) {
$errmsg = "A problem was encountered while attempting to schedule ";
$errmsg .= "the computer back to the available state. Please try ";
$errmsg .= "again at a later time.\n";
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$title = 'Change State to Available Failed';
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
$msg .= "The computer has been scheduled to be moved to the ";
$msg .= "available state at %s.";
$title = "Change to available state";
}
}
# vmhostinuse to maintenance
# vmhostinuse to vmhostinuse with a profile change
elseif(($oldstateid == 20 && $newstateid == 10) ||
($oldstateid == 20 && $newstateid == 20 &&
$oldprofileid != $vmprofileid)) {
if($newstateid == 10) {
$tomaintenance = 1;
$reloadstateid = 18;
}
else {
$tomaintenance = 0;
$reloadstateid = 21;
}
moveReservationsOffVMs($compid);
cleanSemaphore();
$mnid = findManagementNode($compid, unixToDatetime($start), 'future');
$tmp = getCompFinalVMReservationTime($compid, 1, 1);
if($tmp == -1) {
if($tomaintenance) {
$errmsg .= "A problem was encountered while attempting to schedule ";
$errmsg .= "assigned VMs to be moved to the maintenance state. ";
$errmsg .= "Please try again at a later time.\n";
}
else {
$errmsg .= "A problem was encountered while attempting to schedule ";
$errmsg .= "assigned VMs to be moved to the maintenance state while ";
$errmsg .= "the computer is reloaded. Please try again at a later time.\n";
}
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
elseif($tmp > $start)
$delayed = 1;
$vclreloadid = getUserlistID('vclreload@Local');
$start = $tmp;
$end = $start + SECINYEAR;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
$fail = 0;
$vmids = array();
$query = "SELECT vm.id "
. "FROM computer vm, "
. "vmhost v "
. "WHERE v.computerid = $compid AND "
. "vm.vmhostid = v.id";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh)) {
$checkstart = getExistingChangeStateStartTime($row['id'], 18);
if($checkstart) {
if($checkstart > $start)
# update start time of existing tomaintenance reservation
updateExistingToState($row['id'], $startdt, 18);
# leave existing tomaintenance reservation as is
}
elseif(! simpleAddRequest($row['id'], $imageid, $revid, $startdt,
$enddt, 18, $vclreloadid)) {
$fail = 1;
break;
}
$vmids[] = $row['id'];
}
if(count($vmids)) {
$allids = implode(',', $vmids);
$query = "UPDATE computer "
. "SET notes = 'maintenance with host $compid' "
. "WHERE id IN ($allids)";
doQuery($query);
}
cleanSemaphore();
if($fail) {
$errmsg = "A problem was encountered while attempting to schedule ";
$errmsg .= "the VMs to the maintenance state. Please try ";
$errmsg .= "again at a later time.\n";
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
else {
$start = $start + 300;
$end = $start + SECINYEAR;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
$checkstart = getExistingChangeStateStartTime($compid, 18);
if($checkstart) {
if($checkstart > $start)
# update start time of existing tomaintenance reservation
updateExistingToState($compid, $startdt, 18);
# leave existing tomaintenance reservation as is
}
elseif(! simpleAddRequest($compid, $imageid, $revid, $startdt,
$enddt, $reloadstateid, $vclreloadid)) {
if($tomaintenance) {
$errmsg = "A problem was encountered while attempting to schedule ";
$errmsg .= "the node to the maintenance state. Please try ";
$errmsg .= "again at a later time.\n";
}
else {
$errmsg = "A problem was encountered while attempting to schedule ";
$errmsg .= "the node to be reloaded. Please try again at a later time.\n";
}
$errmsg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $errmsg);
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
if($tomaintenance) {
$msg .= "The computer has been scheduled to be moved to the ";
$msg .= "maintenance state at %s.";
$title = "Change to maintenance state";
}
else {
$msg .= "The computer has been scheduled to be reloaded with ";
$msg .= "the selected VM Host Profile at %s.";
$title = "Reload Computer";
}
}
}
# anything else to maintenance
elseif($oldstateid != 10 && $newstateid == 10) {
$mnid = findManagementNode($compid, unixToDatetime($start), 'future');
if(! retryGetSemaphore($imageid, $revid, $mnid, $compid, $start, $end)) {
$errmsg = "An error was encountered while trying to schedule this \n";
$errmsg .= "computer for the maintenance state. Please try again later.\n";
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
return;
}
# create a tomaintenance reservation
$vclreloadid = getUserlistID('vclreload@Local');
if(! (simpleAddRequest($compid, $imageid, $revid, $startdt, $enddt,
18, $vclreloadid))) {
$errmsg = "An error was encountered while trying to schedule this \n";
$errmsg .= "computer for the maintenance state. Please try again later.\n";
$ret = array('status' => 'error',
'errormsg' => $errmsg);
sendJSON($ret);
cleanSemaphore();
return;
}
$msg .= "The computer has been scheduled to be moved to the ";
$msg .= "maintenance state at %s.";
$title = "Change to maintenance state";
}
if($delayed) {
$note = "NOTE: The time for the scheduled change has been updated ";
$note .= "from what was previously reported. \n";
$msg = $note . $msg;
}
$schtime = date('g:i a \o\n n/j/y', $start);
$msg = sprintf($msg, $schtime);
$msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1 ', $msg);
$ret = array('status' => 'success',
'title' => $title,
'clearselection' => 1,
'refreshcount' => $refreshcount,
'msg' => $msg);
sendJSON($ret);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJreloadComputers()
///
/// \brief confirms reloading of computers with specified image
///
/////////////////////////////////////////////////////////////////////////////
function AJreloadComputers() {
$imageid = processInputVar('imageid', ARG_NUMERIC);
$resources = getUserResources(array("imageAdmin", "imageCheckOut"));
if(! array_key_exists($imageid, $resources['image'])) {
$ret = array('status' => 'noaccess');
sendJSON($ret);
return;
}
$compids = $this->validateCompIDs();
if(array_key_exists('error', $compids)) {
$ret = array('status' => 'error', 'errormsg' => $compids['msg']);
sendJSON($ret);
return;
}
if(count($compids) == 0) {
$ret = array('status' => 'noaction');
sendJSON($ret);
return;
}
$computers = $this->getData($this->defaultGetDataArgs);
$imagedata = getImages(0, $imageid);
$reloadnow = array();
$reloadasap = array();
$noreload = array();
foreach($compids as $compid) {
switch($computers[$compid]['state']) {
case "available":
case "failed":
case "reloading":
$reloadnow[] = $compid;
break;
case "inuse":
case "timeout":
case "reserved":
$reloadasap[] = $compid;
break;
case "maintenance":
$noreload[] = $compid;
break;
default:
$noreload[] = $compid;
break;
}
}
$msg = '';
if(count($reloadnow)) {
$msg .= "The following computers will be immediately reloaded with ";
$msg .= "{$imagedata[$imageid]['prettyname']}: \n";
foreach($reloadnow as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($reloadasap)) {
$msg .= "The following computers are currently in use and will have ";
$msg .= "{$imagedata[$imageid]['prettyname']} set as ";
$msg .= "a priority for reloading at the end of the existing reservation ";
$msg .= "on each node: \n";
foreach($reloadasap as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($noreload)) {
$msg .= "The following computers are currently in the maintenance ";
$msg .= "state and therefore will have nothing done to them: \n";
foreach($noreload as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
$cdata = $this->basecdata;
$cdata['imageid'] = $imageid;
$cdata['imagename'] = $imagedata[$imageid]['prettyname'];
$cdata['compids'] = $compids;
$ret = array('status' => 'success',
'title' => "Reload Computers",
'btntxt' => 'Reload Computers',
'actionmsg' => $msg);
if(count($reloadnow) || count($reloadasap)) {
$cont = addContinuationsEntry('AJsubmitReloadComputers', $cdata, SECINDAY, 1, 0);
$ret['cont'] = $cont;
}
else {
$ret['cont'] = '';
$ret['disablesubmit'] = 1;
}
sendJSON($ret);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJsubmitReloadComputers()
///
/// \brief reloads computers with specified image
///
/////////////////////////////////////////////////////////////////////////////
function AJsubmitReloadComputers() {
$data = getContinuationVar(); # imageid, compids, imagename
$start = getReloadStartTime();
$end = $start + 1200; // + 20 minutes
$startstamp = unixToDatetime($start);
$endstamp = unixToDatetime($end);
$imagerevisionid = getProductionRevisionid($data['imageid']);
$computers = $this->getData($this->defaultGetDataArgs);
$reloadnow = array();
$reloadasap = array();
$fails = array();
$passes = array();
foreach($data['compids'] as $compid) {
if($computers[$compid]['state'] == 'available' ||
$computers[$compid]['state'] == 'failed') {
$mn = findManagementNode($compid, unixToDatetime($start), 1);
if($mn == 0) {
$fails[] = $compid;
continue;
}
if(getSemaphore($data['imageid'], $imagerevisionid, $mn, $compid, $startstamp, $endstamp)) {
$query = "SELECT rq.id "
. "FROM request rq, "
. "reservation rs, "
. "state s "
. "WHERE rs.requestid = rq.id AND "
. "rq.stateid = s.id AND "
. "rs.computerid = $compid AND "
. "rq.start < '$endstamp' AND "
. "rq.end > '$startstamp' AND "
. "s.name NOT IN ('complete', 'deleted', 'failed', 'timeout')";
$qh = doQuery($query);
if(! mysql_num_rows($qh))
$reloadnow[] = $compid;
else
$reloadasap[] = $compid;
}
else
$reloadasap[] = $compid;
}
}
$vclreloadid = getUserlistID('vclreload@Local');
foreach($reloadnow as $compid) {
if(simpleAddRequest($compid, $data['imageid'], $imagerevisionid, $startstamp, $endstamp, 19, $vclreloadid))
$passes[] = $compid;
else
$fails[] = $compid;
}
// release semaphore lock on nodes
cleanSemaphore();
if(count($reloadasap)) {
$compids = implode(',', $reloadasap);
$query = "UPDATE computer "
. "SET nextimageid = {$data['imageid']} "
. "WHERE id IN ($compids)";
doQuery($query, 101);
}
$msg = '';
if(count($passes)) {
$msg .= "The following computers are being immediately reloaded with ";
$msg .= "{$data['imagename']}: \n";
foreach($passes as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
}
if(count($reloadasap)) {
if(count($passes))
$msg .= " ";
$msg .= "The following computers have {$data['imagename']} ";
$msg .= "set as a priority for reloading at the end of their existing ";
$msg .= "reservations: \n";
foreach($reloadasap as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
}
if(count($fails)) {
if(count($passes) || count($reloadasap))
$msg .= " ";
$msg .= "No functional management node was found for the following ";
$msg .= "computers. They could not be reloaded at this time: \n";
foreach($fails as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
}
$ret = array('status' => 'success',
'title' => "Reload Computers",
'refreshcount' => 4,
'msg' => $msg);
sendJSON($ret);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJdeleteComputers()
///
/// \brief confirms deleting submitted computers
///
/////////////////////////////////////////////////////////////////////////////
function AJdeleteComputers() {
$compids = $this->validateCompIDs();
if(array_key_exists('error', $compids)) {
$ret = array('status' => 'error', 'errormsg' => $compids['msg']);
sendJSON($ret);
return;
}
if(count($compids) == 0) {
$ret = array('status' => 'noaction');
sendJSON($ret);
return;
}
$compdata = $this->getData($this->defaultGetDataArgs);
$skipcompids = array();
$allids = implode(',', $compids);
$query = "SELECT rs.computerid "
. "FROM reservation rs, "
. "request rq, "
. "state s "
. "WHERE rs.requestid = rq.id AND "
. "rq.stateid = s.id AND "
. "rs.computerid in ($allids) AND "
. "s.name NOT IN ('deleted', 'failed', 'complete') AND "
. "rq.end > NOW()";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh))
$skipcompids[] = $row['computerid'];
$query = "SELECT DISTINCT bc.computerid "
. "FROM blockTimes bt, "
. "blockComputers bc, "
. "blockRequest br "
. "WHERE bc.computerid in ($allids) AND "
. "bc.blockTimeid = bt.id AND "
. "bt.blockRequestid = br.id AND "
. "bt.end > NOW() AND "
. "bt.skip = 0 AND "
. "br.status = 'accepted'";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh))
$skipcompids[] = $row['computerid'];
$delids = array_diff($compids, $skipcompids);
$msg = '';
if(count($delids)) {
$msg .= "Delete the following computers?
\n";
foreach($delids as $id)
$msg .= "{$compdata[$id]['hostname']} \n";
$msg .= ' ';
}
if(count($skipcompids)) {
$msg .= "The following computers are currently in use and cannot be ";
$msg .= "deleted at this time:
\n";
$msg .= "\n";
foreach($skipcompids as $id)
$msg .= "{$compdata[$id]['hostname']} \n";
$msg .= "\n";
$msg .= " \n";
}
$cdata = $this->basecdata;
$cdata['compids'] = $delids;
$ret = array('status' => 'success',
'title' => "Delete Computers",
'btntxt' => 'Delete Computers',
'actionmsg' => $msg);
if(count($delids)) {
$cont = addContinuationsEntry('AJsubmitDeleteComputers', $cdata, SECINDAY, 1, 0);
$ret['cont'] = $cont;
}
else {
$ret['cont'] = '';
$ret['disablesubmit'] = 1;
}
sendJSON($ret);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJsubmitDeleteComputers()
///
/// \brief flags submitted computers as deleted
///
/////////////////////////////////////////////////////////////////////////////
function AJsubmitDeleteComputers() {
$compids = getContinuationVar('compids');
$start = getReloadStartTime();
$end = $start + 1200; // + 20 minutes
$startstamp = unixToDatetime($start);
$endstamp = unixToDatetime($end);
$computers = $this->getData($this->defaultGetDataArgs);
$fails = array();
$passes = array();
# get ids from getUserResources because that data should already be in cache
$resources = getUserResources(array("imageAdmin", "imageCheckOut"));
$tmp = array_keys($resources['image']);
$imageid = $tmp[0];
$revid = getProductionRevisionid($imageid);
$tmp = array_keys($resources['managementnode']);
$mnid = $tmp[0];
foreach($compids as $compid) {
if(retryGetSemaphore($imageid, $revid, $mnid, $compid, $startstamp, $endstamp))
$passes[] = $compid;
else
$fails[] = $compid;
}
$allids = implode(',', $passes);
$query = "SELECT rs.computerid "
. "FROM reservation rs, "
. "request rq, "
. "state s "
. "WHERE rs.requestid = rq.id AND "
. "rq.stateid = s.id AND "
. "rs.computerid in ($allids) AND "
. "s.name NOT IN ('deleted', 'failed', 'complete') AND "
. "rq.end > NOW()";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh))
$fails[] = $row['computerid'];
$delids = array_diff($compids, $fails);
# FIXME this will throw an error if two computers will end up with the
# same hostname after -UNDELETED-ID gets removed
$allids = implode(',', $delids);
$query = "UPDATE computer "
. "SET deleted = 1, "
. "datedeleted = NOW(), "
. "hostname = REPLACE(hostname, CONCAT('-UNDELETED-', id), ''), "
. "vmhostid = NULL "
. "WHERE id IN ($allids)";
doQuery($query);
// release lock
cleanSemaphore();
if(count($delids)) {
$msg = "The following computers were deleted:
\n";
foreach($delids as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " ";
}
if(count($fails)) {
$msg .= "The following computers are currently in use and could not be ";
$msg .= "deleted at this time:
\n";
$msg .= "\n";
foreach($fails as $id)
$msg .= "{$compdata[$id]['hostname']} \n";
$msg .= " \n";
$msg .= "\n";
}
# clear user resource cache for this type
$key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 1, 0, 0));
unset($_SESSION['userresources'][$key]);
$key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 0, 0, 0));
unset($_SESSION['userresources'][$key]);
$ret = array('status' => 'success',
'title' => "Delete Computers",
'clearselection' => 1,
'refreshcount' => 1,
'msg' => $msg);
sendJSON($ret);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJcompStateChange()
///
/// \brief confirms changing state of submitted computers
///
/////////////////////////////////////////////////////////////////////////////
function AJcompStateChange() {
$newstateid = processInputVar('stateid', ARG_NUMERIC);
$states = getContinuationVar('states');
if(! array_key_exists($newstateid, $states)) {
$ret = array('status' => 'noaction');
sendJSON($ret);
return;
}
$cdata = $this->basecdata;
$cdata['newstateid'] = $newstateid;
$tmp = getUserResources(array($this->restype . "Admin"), array("administer"), 0, 1);
$computers = $tmp['computer'];
$msg = '';
$complist = '';
$compids = $this->validateCompIDs();
if($newstateid == 2) {
$msg .= "You are about to place the following computers into the ";
$msg .= "available state:
\n";
foreach($compids as $compid)
$complist .= $computers[$compid] . " \n";
$complist .= " \n";
$cdata['compids'] = $compids;
}
elseif($newstateid == 10) {
$msg .= "Please enter a reason you are changing the following computers to ";
$msg .= "the maintenance state:
\n";
$msg .= "
\n";
$msg .= "These computers will be placed into the maintenance state:
\n";
foreach($compids as $compid)
$complist .= $computers[$compid] . " \n";
$complist .= " \n";
$cdata['compids'] = $compids;
}
elseif($newstateid == 20) {
$profiles = getVMProfiles();
$cdata['profiles'] = $profiles;
$msg .= "Select a VM Host Profile to use on the selected computers:";
$msg .= "
\n";
$msg .= "These computers will be deployed as VM Hosts:
\n";
foreach($compids as $compid)
$complist .= $computers[$compid] . " \n";
$complist .= " \n";
$cdata['compids'] = $compids;
}
elseif($newstateid == 23) {
$msg .= "These computers will be placed into the hpc state:
\n";
foreach($compids as $compid)
$complist .= $computers[$compid] . " \n";
$complist .= " \n";
$cdata['compids'] = $compids;
}
$cont = addContinuationsEntry('AJsubmitCompStateChange', $cdata, SECINDAY, 1, 0);
$ret = array('status' => 'success',
'title' => "State Change",
'btntxt' => 'Submit State Change',
'cont' => $cont,
'actionmsg' => $msg,
'complist' => $complist);
sendJSON($ret);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJsubmitCompStateChange()
///
/// \brief changes state of submitted computers
///
/////////////////////////////////////////////////////////////////////////////
function AJsubmitCompStateChange() {
global $user;
$newstateid = getContinuationVar('newstateid');
$compids = getContinuationVar('compids');
$states = getStates();
$ret = array('status' => 'success',
'title' => "Change State",
'clearselection' => 0,
'newstate' => $states[$newstateid],
'refreshcount' => 1);
# get ids from getUserResources because that data should already be in cache
$resources = getUserResources(array("imageAdmin", "imageCheckOut"));
$tmp = array_keys($resources['image']);
$semimageid = $tmp[0];
$semrevid = getProductionRevisionid($semimageid);
if(! empty($resources['managementnode'])) {
$tmp = array_keys($resources['managementnode']);
$semmnid = $tmp[0];
}
else {
$allmns = array_keys(getManagementNodes('future'));
if(empty($allmns)) {
$ret = array('status' => 'error', 'errormsg' => 'No management nodes are available for controlling the submitted computers.');
sendJSON($ret);
return;
}
$semmnid = $allmns[0];
}
if($newstateid == 2) {
$fails = array('provnone' => array(),
'reserved' => array(),
'hostfail' => array(),
'hasvms' => array());
$availablenow = array();
$checkvms = array();
$checkhosts = array();
$noaction = array();
$computers = $this->getData($this->defaultGetDataArgs);
$inusecompids = array();
$allids = implode(',', $compids);
$query = "SELECT rs.computerid "
. "FROM reservation rs, "
. "request rq "
. "WHERE rs.requestid = rq.id AND "
. "rq.end > NOW() AND "
. "rq.start < NOW() AND "
. "rq.stateid NOT IN (1, 5, 11, 12) AND " # TODO might not want 11 (timeout)
. "rs.computerid IN ($allids)";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh))
$inusecompids[$row['computerid']] = 1;
# check initial conditions
foreach($compids as $compid) {
# already in available
if($computers[$compid]['state'] == 'available') {
$noaction[] = $compid;
continue;
}
# no provisioning engine
if($computers[$compid]['provisioning'] == 'None') {
$fails['provnone'][] = $compid;
continue;
}
# non-VM in maintenance without a vmhost entry or in hpc
if($computers[$compid]['state'] == 'hpc' ||
($computers[$compid]['state'] == 'maintenance' &&
is_null($computers[$compid]['vmprofileid']) &&
$computers[$compid]['type'] != 'virtualmachine')) {
$availablenow[] = $compid;
continue;
}
# has active reservation
if(array_key_exists($compid, $inusecompids)) {
$fails['reserved'][] = $compid;
continue;
}
# in reload, reloading, reserved, inuse, or failed with no active reservation
if(preg_match('/^(reload|reloading|reserved|inuse|failed|timeout)$/',
$computers[$compid]['state'])) {
$availablenow[] = $compid;
continue;
}
# vmhostinuse - check for assigned VMs
if($computers[$compid]['state'] == 'vmhostinuse') {
$checkvms[] = $compid;
continue;
}
# VM in maintenance
if($computers[$compid]['state'] == 'maintenance' &&
$computers[$compid]['type'] == 'virtualmachine') {
$checkhosts[] = $compid;
continue;
}
# maintenance - check for previously being a vmhost
if($computers[$compid]['state'] == 'maintenance' &&
! is_null($computers[$compid]['vmprofileid'])) {
$checkvms[] = $compid;
continue;
}
}
if(count($checkvms)) {
$ids = implode(',', $checkvms);
$query = "SELECT h.id, "
. "COUNT(vm.id) AS count "
. "FROM computer h "
. "LEFT JOIN vmhost vh ON (h.id = vh.computerid) "
. "LEFT JOIN computer vm ON (vh.id = vm.vmhostid) "
. "WHERE h.id IN ($ids) "
. "GROUP BY vh.computerid";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh)) {
if($row['count'])
$fails['hasvms'][] = $row['id'];
else
$availablenow[] = $row['id'];
}
}
if(count($checkhosts)) {
$ids = implode(',', $checkhosts);
$query = "SELECT h.stateid, "
. "vm.id "
. "FROM computer vm "
. "LEFT JOIN vmhost vh ON (vm.vmhostid = vh.id) "
. "LEFT JOIN computer h ON (vh.computerid = h.id) "
. "WHERE vm.id IN ($ids)";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh)) {
if($row['stateid'] != 20)
$fails['hostfail'][] = $row['id'];
else
$availablenow[] = $row['id'];
}
}
if(count($availablenow)) {
$allids = implode(',', $availablenow);
$query = "UPDATE computer "
. "SET stateid = 2, "
. "notes = '' "
. "WHERE id IN ($allids)";
doQuery($query);
}
$msg = '';
if(count($noaction)) {
$msg .= "The following computers were already in the available ";
$msg .= "state:
\n";
foreach($noaction as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($availablenow)) {
$msg .= "The following computers were changed to the available ";
$msg .= "state:
\n";
foreach($availablenow as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($fails['provnone'])) {
$msg .= "\n";
$msg .= "The following computers cannot be in the available state ";
$msg .= "because they have no provisioning engine:
\n";
foreach($fails['provnone'] as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($fails['reserved'])) {
$msg .= "\n";
$msg .= "The following computers are currently in use and could not have ";
$msg .= "their states changed at this time:
\n";
foreach($fails['reserved'] as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($fails['hasvms'])) {
$msg .= "\n";
$msg .= "The following computers currently have VMs assigned to them ";
$msg .= "and cannot be moved to available until the VMs are removed:";
$msg .= "
\n";
foreach($fails['hasvms'] as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($fails['hostfail'])) {
$msg .= "\n";
$msg .= "The following VMs are not currently assigned to a host in ";
$msg .= "the vmhostinuse state:
\n";
foreach($fails['hostfail'] as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
}
# switching to maintenance or hpc
elseif($newstateid == 10 || $newstateid == 23) {
if($newstateid == 10) {
$notes = processInputVar('notes', ARG_STRING);
if(get_magic_quotes_gpc())
$notes = stripslashes($notes);
$notes = mysql_real_escape_string($notes);
$notes = $user["unityid"] . " " . unixToDatetime(time()) . "@"
. $notes;
}
$vclreloadid = getUserlistID('vclreload@Local');
$computers = $this->getData($this->defaultGetDataArgs);
$noaction = array();
$changenow = array();
$changeasap = array();
$changetimes = array();
$vmwithhost = array();
$fails = array();
$semstart = unixToDatetime(time());
$semend = '2038-01-01 00:00:00';
foreach($compids as $compid) {
if($newstateid == 10 &&
$computers[$compid]['type'] == 'virtualmachine' &&
in_array($computers[$compid]['vmhostcomputerid'], $compids))
$vmwithhost[] = $compid;
if(($newstateid == 10 && $computers[$compid]['state'] == 'maintenance') ||
($newstateid == 23 && $computers[$compid]['state'] == 'hpc')) {
$noaction[] = $compid;
continue;
}
# try to move future reservations off of computer
moveReservationsOffComputer($compid);
cleanSemaphore();
$reloadstart = getCompFinalReservationTime($compid);
if($computers[$compid]['state'] == 'vmhostinuse') {
$sem = array('imageid' => $semimageid, 'revid' => $semrevid,
'mnid' => $semmnid, 'start' => $semstart, 'end' => $semend);
moveReservationsOffVMs($compid, $sem);
cleanSemaphore();
$reloadstart = getCompFinalVMReservationTime($compid, 1, 1);
if($reloadstart == -1) {
cleanSemaphore();
$fails[] = $compid;
continue;
}
elseif($reloadstart > 0) {
if(unixToDatetime($reloadstart) == '2038-01-01 00:00:00') {
# host has a VM reserved indefintely
$fails[] = $compid;
continue;
}
# schedule tomaintenance/tohpc reservations for VMs and host
$noimageid = getImageId('noimage');
$revid = getProductionRevisionid($noimageid);
$startdt = unixToDatetime($reloadstart);
$end = $reloadstart + SECINMONTH;
$enddt = unixToDatetime($end);
$query = "SELECT vm.id "
. "FROM computer vm, "
. "vmhost v "
. "WHERE v.computerid = $compid AND "
. "vm.vmhostid = v.id";
$qh = doQuery($query);
$setnoteids = array();
while($row = mysql_fetch_assoc($qh)) {
$checkstart = getExistingChangeStateStartTime($row['id'], 18);
if($checkstart) {
if($checkstart > $reloadstart)
# update start time of existing tomaintenance reservation
updateExistingToState($row['id'], $startdt, 18);
# leave existing tomaintenance reservation as is
}
# add tomaintenance reservation
elseif(! simpleAddRequest($row['id'], $noimageid, $revid, $startdt,
$enddt, 18, $vclreloadid)) {
cleanSemaphore();
$fails[] = $compid;
continue(2); # jump out of while, continue with foreach loop
}
$setnoteids[] = $row['id'];
}
if($newstateid == 10 && count($setnoteids)) {
$inids = implode(',', $setnoteids);
$query = "UPDATE computer "
. "SET notes = 'maintenance with host $compid' "
. "WHERE id IN ($inids)";
doQuery($query);
}
$start = $reloadstart + 300; # allow 5 minutes for VMs to get removed
$startdt = unixToDatetime($start);
# lock this computer
if(! retryGetSemaphore($semimageid, $semrevid, $semmnid, $compid, $startdt, $enddt)) {
cleanSemaphore();
$fails[] = $compid;
continue;
}
if($newstateid == 10)
$tostateid = 18;
else
$tostateid = 22;
$checkstart = getExistingChangeStateStartTime($compid, $tostateid);
if($checkstart) {
if($checkstart > $start)
# update start time of existing tomaintenance/tohpc reservation
updateExistingToState($compid, $startdt, $tostateid);
# leave existing tomaintenance/tohpc reservation as is
}
elseif(! simpleAddRequest($compid, $noimageid, $revid, $startdt,
$enddt, $tostateid, $vclreloadid)) {
cleanSemaphore();
$fails[] = $compid;
continue;
}
cleanSemaphore();
$changetimes[$compid] = $start;
$changeasap[] = $compid;
continue;
}
else {
if($newstateid == 10)
$note = "maintenance with host $compid";
else
$note = "maintenance so $compid can go to hpc";
# no VMs or no reservations on assigned VMs
$query = "UPDATE computer c "
. "INNER JOIN vmhost v ON (c.vmhostid = v.id) "
. "SET c.stateid = 10, "
. "c.notes = '$note' "
. "WHERE v.computerid = $compid";
doQuery($query);
}
}
elseif($reloadstart) {
if(unixToDatetime($reloadstart) == '2038-01-01 00:00:00') {
# node is reserved indefintely
$fails[] = $compid;
continue;
}
# computer has reservations, schedule tomaintenance
$noimageid = getImageId('noimage');
$revid = getProductionRevisionid($noimageid);
$startdt = unixToDatetime($reloadstart);
$end = $reloadstart + SECINMONTH;
$enddt = unixToDatetime($end);
# lock this computer
if(! retryGetSemaphore($semimageid, $semrevid, $semmnid, $compid, $startdt, $enddt)) {
$fails[] = $compid;
cleanSemaphore();
continue;
}
if($newstateid == 10)
$tostateid = 18;
else
$tostateid = 22;
$checkstart = getExistingChangeStateStartTime($compid, $tostateid);
if($checkstart) {
if($checkstart > $reloadstart)
# update start time of existing tomaintenance/tohpc reservation
updateExistingToState($compid, $startdt, $tostateid);
else
# leave existing tomaintenance/tohpc reservation as is
$reloadstart = $checkstart;
}
elseif(! simpleAddRequest($compid, $noimageid, $revid, $startdt,
$enddt, $tostateid, $vclreloadid)) {
$fails[] = $compid;
cleanSemaphore();
continue;
}
cleanSemaphore();
$changetimes[$compid] = $reloadstart;
$changeasap[] = $compid;
continue;
}
# change to maintenance/tohpc state and save in $changenow
// if we wait and put them all in maintenance/hpc at the same time,
# we may end up moving reservations to the computer later in the
# loop
# lock this computer
if(! retryGetSemaphore($semimageid, $semrevid, $semmnid, $compid, $semstart, $semend)) {
$fails[] = $compid;
cleanSemaphore();
continue;
}
$query = "UPDATE computer "
. "SET stateid = $newstateid "
. "WHERE id = $compid";
doQuery($query, 101);
$changenow[] = $compid;
cleanSemaphore();
}
if($newstateid == 10 && (count($noaction) || count($changeasap))) {
$comparr = array_merge($noaction, $changeasap);
$allids = implode(',', $comparr);
if(count($vmwithhost))
$skipids = implode(',', $vmwithhost);
else
$skipids = "''";
$query = "UPDATE computer "
. "SET notes = '$notes' "
. "WHERE id IN ($allids) AND "
. "id NOT IN ($skipids)";
doQuery($query, 101);
$updatevms = array_intersect($vmwithhost, $comparr);
if(count($updatevms)) {
$inids = implode(',', $updatevms);
$query = "UPDATE computer vm "
. "INNER JOIN vmhost v ON (vm.vmhostid = v.id) "
. "SET vm.notes = CONCAT('maintenance with host ', v.computerid) "
. "WHERE vm.id IN ($inids)";
doQuery($query);
}
}
if($newstateid == 10)
$newstate = 'maintenance';
else
$newstate = 'hpc';
$msg = '';
if(count($changenow)) {
$msg .= "The following computers were immediately placed into the ";
$msg .= "$newstate state:
\n";
$msg .= "\n";
foreach($changenow as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($changeasap)) {
$msg .= "The following computers are currently reserved ";
$msg .= "and will be placed in the $newstate state at the time listed ";
$msg .= "for each computer:\n";
$msg .= "
\n";
$msg .= " \n";
}
if(count($fails)) {
$msg .= "The following computers are currently reserved ";
$msg .= "but could not be scheduled to be moved to the $newstate state ";
$msg .= "at this time:
\n";
$msg .= "\n";
foreach($fails as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($noaction)) {
$msg .= "The following computers were already in the $newstate state";
if($newstateid == 10)
$msg .= " and had their notes on being in the maintenance state updated";
$msg .= ":
\n";
foreach($changenow as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
$ret['clearselection'] = 1;
$ret['refreshcount'] = 5;
}
if(count($changenowreload)) {
$msg .= "The following computers have been scheduled to be immediately reloaded \n";
$msg .= "and placed into the vmhostinuse state:
\n";
foreach($changenowreload as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
$ret['clearselection'] = 1;
$ret['refreshcount'] = 5;
}
if(count($changeasap)) {
$msg .= "The following computers are currently reserved and have been scheduled \n";
$msg .= "to be reloaded and placed into the vmhostinuse state at the time listed \n";
$msg .= "for each computers:
\n";
$msg .= " \n";
}
if(count($fails)) {
$msg .= "Problems were encountered while trying to move the following computers \n";
$msg .= "to the vmhostinuse state:
\n";
foreach($fails as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($vmnotallowed)) {
$msg .= "The following computers are VMs which cannot be placed into the ";
$msg .= "vmhostinuse state:
\n";
foreach($vmnotallowed as $compid)
$msg .= "{$computers[$compid]['hostname']} \n";
$msg .= " \n";
}
if(count($noaction)) {
$msg .= "The following computers were already in the vmhostinuse state:
\n";
foreach($nowids as $compid)
$msg .= "{$compdata[$compid]} \n";
$msg .= " ";
}
if(count($fails)) {
$msg .= "The following computers have or will soon have reservations ";
$msg .= "on them and could not have their Provisioning Engine changed ";
$msg .= "at this time:
\n";
$compids = array_diff($compids, $inusecompids);
}
if(count($compids)) {
if($natenabled) {
$msg .= "Enable Connect Using NAT and set the NAT ";
$msg .= "host to {$nathosts[$nathostid]['hostname']}";
$msg .= " for the following computers?
";
}
else {
$msg .= "Disable Connect Using NAT for the following ";
$msg .= "computers?
";
$ret = array('status' => 'onestep',
'title' => 'Generate /etc/hosts Data',
'actionmsg' => $msg);
sendJSON($ret);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn validateCompIDs()
///
/// \return array of computerids; if user does not have access to any
/// submitted computers, returns array with 'error' set to 1 and 'msg' set
/// to an error message listing computers the user does not have access to
///
/// \brief validates user access to submitted computers
///
/////////////////////////////////////////////////////////////////////////////
function validateCompIDs() {
$compids = processInputVar('compids', ARG_MULTINUMERIC);
$resources = getUserResources(array($this->restype . "Admin"), array("administer"), 0, 1);
$usercomps = $resources[$this->restype];
$noaccess = array();
foreach($compids as $id) {
if(! array_key_exists($id, $usercomps))
$noaccess[] = $usercomps[$id];
}
if(count($noaccess)) {
$ret = array('error' => 1);
$ret['msg'] = "Access denied to these computers:
" . implode(' ', $noaccess) . "
";
return $ret;
}
return $compids;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn scheduleVMsToAvailable()
///
/// \param $vmids - array of ids of VMs to set schedule to available state
///
/// \brief sets VMs to failed state so that they cannot be scheduled and
/// creates a reload reservation for the noimage image
///
/////////////////////////////////////////////////////////////////////////////
function scheduleVMsToAvailable($vmids) {
# TODO test with vcld that will handle reservation for noimage okay
# schedule $vmids to have noimage "loaded" on them in 15 minutes
$allids = implode(',', $vmids);
$query = "UPDATE computer "
. "SET stateid = 5, " # set to failed instead of available so cannot be scheduled by users
. "notes = '' "
. "WHERE id IN ($allids)";
doQuery($query);
$imageid = getImageId('noimage');
$revid = getProductionRevisionid($imageid);
$start = time() + 900;
$end = $start + 3600;
$startdt = unixToDatetime($start);
$enddt = unixToDatetime($end);
$vclreloadid = getUserlistID('vclreload@Local');
foreach($vmids as $vmid)
// if simpleAddRequest fails, vm is left assigned and in failed state, which is fine
simpleAddRequest($vmid, $imageid, $revid, $startdt,
$enddt, 19, $vclreloadid);
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn checkMultiAddMacs($startmac, $cnt, &$errmsg, &$macs)
///
/// \param $startmac - starting mac address
/// \param $cnt - number of computers for which to generate addresses
/// \param $errmsg - if conflict, error message is put in here
/// \param $macs - array of generated addresses is put in here
///
/// \return 1 if error; 0 if success
///
/// \brief generates all required mac addresses for adding multiple
/// computers; checks that there are no duplicates with existing computers
///
/////////////////////////////////////////////////////////////////////////////
function checkMultiAddMacs($startmac, $cnt, &$errmsg, &$macs) {
$tmp = explode(':', $startmac);
$topdec = hexdec($tmp[0] . $tmp[1] . $tmp[2]);
$botdec = hexdec($tmp[3] . $tmp[4] . $tmp[5]);
$topmac = "{$tmp[0]}:{$tmp[1]}:{$tmp[2]}";
$topplus = implode(':', str_split(dechex($topdec + 1), 2));
$start = $botdec;
$macs = array();
$eth0macs = array();
$eth1macs = array();
$toggle = 0;
$end = $start + ($cnt * 2);
for($i = $start; $i < $end; $i++) {
if($i > 16777215) {
$val = $i - 16777216;
$tmp = sprintf('%06x', $val);
$tmp2 = str_split($tmp, 2);
$macs[] = $topplus . ':' . implode(':', $tmp2);
}
else {
$tmp = sprintf('%06x', $i);
$tmp2 = str_split($tmp, 2);
$macs[] = $topmac . ':' . implode(':', $tmp2);
}
if($toggle % 2)
$eth1macs[] = $topmac . ':' . implode(':', $tmp2);
else
$eth0macs[] = $topmac . ':' . implode(':', $tmp2);
$toggle++;
}
$ineth0s = implode("','", $eth0macs);
$ineth1s = implode("','", $eth1macs);
$query = "SELECT id "
. "FROM computer "
. "WHERE eth0macaddress IN ('$ineth0s') OR "
. "eth1macaddress IN ('$ineth1s')";
$qh = doQuery($query);
$errmsg = '';
if(mysql_num_rows($qh)) {
$errmsg .= "The specified starting MAC address combined with the number ";
$errmsg .= "of computers entered will result in a MAC address already ";
$errmsg .= "assigned to another computer.";
return 1;
}
elseif($i > 16777215 && $topdec == 16777215) {
$errmsg .= "Starting MAC address too large for given given number of machines";
return 1;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
///
/// \fn AJaddRemGroupResource()
///
/// \brief adds or removes groups for a computer and sends JSON response;
/// overridden from base class to handle case of adding multiple computers
/// and being able to assign them all to a computer group at once
///
/////////////////////////////////////////////////////////////////////////////
function AJaddRemGroupResource() {
$newids = getContinuationVar('newids');
if(is_null($newids)) {
$rscid = processInputVar('id', ARG_NUMERIC);
$resources = getUserResources(array($this->restype . "Admin"), array("manageGroup"));
if(! array_key_exists($rscid, $resources[$this->restype])) {
$arr = array('status' => 'noaccess');
sendJSON($arr);
return;
}
}
$groups = getUserResources(array($this->restype . "Admin"), array("manageGroup"), 1);
$tmp = processInputVar('listids', ARG_STRING);
$tmp = explode(',', $tmp);
$groupids = array();
foreach($tmp as $id) {
if(! is_numeric($id))
continue;
if(! array_key_exists($id, $groups[$this->restype])) {
$arr = array('status' => 'noaccess');
sendJSON($arr);
return;
}
$groupids[] = $id;
}
$args = $this->defaultGetDataArgs;
if(is_null($newids))
$args['rscid'] = $rscid;
$resdata = $this->getData($args);
$mode = getContinuationVar('mode');
if($mode == 'add') {
$adds = array();
if(is_null($newids)) {
foreach($groupids as $id)
$adds[] = "({$resdata[$rscid]['resourceid']}, $id)";
}
else {
foreach($newids as $newrscid) {
foreach($groupids as $id)
$adds[] = "({$resdata[$newrscid]['resourceid']}, $id)";
}
}
$query = "INSERT IGNORE INTO resourcegroupmembers "
. "(resourceid, resourcegroupid) VALUES ";
$query .= implode(',', $adds);
doQuery($query);
}
else {
$rems = implode(',', $groupids);
if(is_null($newids))
$query = "DELETE FROM resourcegroupmembers "
. "WHERE resourceid = {$resdata[$rscid]['resourceid']} AND "
. "resourcegroupid IN ($rems)";
else {
$allrscids = array();
foreach($newids as $newrscid)
$allrscids[] = $resdata[$newrscid]['resourceid'];
$allrscids = implode(',', $allrscids);
$query = "DELETE FROM resourcegroupmembers "
. "WHERE resourceid IN ($allrscids) AND "
. "resourcegroupid IN ($rems)";
}
doQuery($query);
}
$_SESSION['userresources'] = array();
$regids = "^" . implode('$|^', $groupids) . "$";
$arr = array('status' => 'success',
'regids' => $regids,
'inselobj' => 'ingroups',
'outselobj' => 'outgroups');
sendJSON($arr);
}
}
?>