Added: vcl/trunk/web/.ht-inc/computer.php URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/computer.php?rev=1624325&view=auto ============================================================================== --- vcl/trunk/web/.ht-inc/computer.php (added) +++ vcl/trunk/web/.ht-inc/computer.php Thu Sep 11 16:01:48 2014 @@ -0,0 +1,4354 @@ +<?php +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \class Computer +/// +/// \brief extends Resource class to add things specific to resources of the +/// computer type +/// +//////////////////////////////////////////////////////////////////////////////// +class Computer extends Resource { + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn __construct() + /// + /// \brief calls parent constructor; initializes things for Computer class + /// + ///////////////////////////////////////////////////////////////////////////// + function __construct() { + parent::__construct(); + $this->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 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'; + } + return ucfirst($field); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn extraResourceFilters() + /// + /// \return html + /// + /// \brief generates HTML for computer utilities drop down and filtering by + /// computer group + /// + ///////////////////////////////////////////////////////////////////////////// + function extraResourceFilters() { + $h = ''; + + # selected items menu + $h .= "<div dojoType=\"dijit.form.DropDownButton\">\n"; + $h .= "<span>" . _("Actions for selected computers") . "</span>\n"; + $h .= "<div dojoType=\"dijit.Menu\" id=\"actionmenu\">\n"; + + # reload + $resources = getUserResources(array("imageAdmin", "imageCheckOut")); + if(count($resources['image'])) { + $h .= " <div dojoType=\"dijit.PopupMenuItem\">\n"; + $h .= " <span>Reload with an Image</span>\n"; + $h .= " <div dojoType=\"dijit.layout.ContentPane\"\n"; + $h .= " style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n"; + $h .= " Reload computers with the following image:<br>\n"; + $h .= selectInputAutoDijitHTML('', $resources['image'], 'reloadimageid'); + $cont = addContinuationsEntry('AJreloadComputers', $this->basecdata); + $h .= " <input type=\"hidden\" id=\"reloadcont\" value=\"$cont\"><br>\n"; + $h .= dijitButton('', 'Confirm Reload Computers', 'confirmReload();', 0); + $h .= " </div>\n"; + $h .= " </div>\n"; + } + + # delete + $h .= " <div dojoType=\"dijit.MenuItem\"\n"; + $h .= " onClick=\"confirmDelete\">\n"; + $h .= " Delete Computers\n"; + $cont = addContinuationsEntry('AJdeleteComputers', $this->basecdata); + $h .= " <input type=\"hidden\" id=\"deletecont\" value=\"$cont\"><br>\n"; + $h .= " </div>\n"; + + # change state + $states = array("2" => "available", + "23" => "hpc", + "10" => "maintenance", + "20" => "convert to vmhostinuse"); + $h .= " <div dojoType=\"dijit.PopupMenuItem\">\n"; + $h .= " <span>Change State</span>\n"; + $h .= " <div dojoType=\"dijit.layout.ContentPane\"\n"; + $h .= " style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n"; + $h .= " Change state to:<br>\n"; + $h .= selectInputAutoDijitHTML('', $states, 'newstateid'); + $cdata = $this->basecdata; + $cdata['states'] = $states; + $cont = addContinuationsEntry('AJcompStateChange', $cdata); + $h .= " <input type=\"hidden\" id=\"statechangecont\" value=\"$cont\"><br>\n"; + $h .= dijitButton('', 'Confirm State Change', 'confirmStateChange();', 0); + $h .= " </div>\n"; + $h .= " </div>\n"; + + # change schedule + $resources = getUserResources(array("scheduleAdmin"), array("manageGroup")); + if(count($resources['schedule'])) { + $h .= " <div dojoType=\"dijit.PopupMenuItem\">\n"; + $h .= " <span>Change Schedule</span>\n"; + $h .= " <div dojoType=\"dijit.layout.ContentPane\"\n"; + $h .= " style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n"; + $h .= " Change schedule to:<br>\n"; + $h .= selectInputAutoDijitHTML('', $resources['schedule'], 'newscheduleid'); + $cont = addContinuationsEntry('AJcompScheduleChange', $this->basecdata); + $h .= " <input type=\"hidden\" id=\"schedulecont\" value=\"$cont\"><br>\n"; + $h .= dijitButton('', 'Confirm Schedule Change', 'confirmScheduleChange();', 0); + $h .= " </div>\n"; + $h .= " </div>\n"; + } + + # change provisioning engine + $provisioning = getProvisioning(); + $h .= " <div dojoType=\"dijit.PopupMenuItem\">\n"; + $h .= " <span>Change Provisioning Engine</span>\n"; + $h .= " <div dojoType=\"dijit.layout.ContentPane\"\n"; + $h .= " style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n"; + $h .= " Change Provisioning Engine to:<br>\n"; + $h .= selectInputAutoDijitHTML('', $provisioning, 'newprovisioningid'); + $cdata = $this->basecdata; + $cont = addContinuationsEntry('AJcompProvisioningChange', $cdata); + $h .= " <input type=\"hidden\" id=\"provisioningchangecont\" value=\"$cont\"><br>\n"; + $h .= dijitButton('', 'Confirm Provisioning Engine Change', 'confirmProvisioningChange();', 0); + $h .= " </div>\n"; + $h .= " </div>\n"; + + # generate private dhcpd data + $h .= " <div dojoType=\"dijit.PopupMenuItem\">\n"; + $h .= " <span>Generate Private dhcpd Data</span>\n"; + $h .= " <div dojoType=\"dijit.layout.ContentPane\"\n"; + $h .= " style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n"; + $h .= " Enter the Management Node Private IP Address:<br>\n"; + $h .= " <input type=\"text\" dojoType=\"dijit.form.TextBox\" id=\"mnprivipaddr\" "; + $h .= "required=\"false\"><br><br>\n"; + $h .= " Select which NIC is used for the Private interface:<br>\n"; + $h .= " <input type=\"radio\" name=\"prnic\" value=\"eth0\" id=\"preth0rdo\" "; + $h .= "checked=\"checked\"><label for=\"eth0rdo\">eth0</label><br>\n"; + $h .= " <input type=\"radio\" name=\"prnic\" value=\"eth1\" id=\"preth1rdo\">"; + $h .= "<label for=\"eth1rdo\">eth1</label><br>\n"; + $h .= dijitButton('', 'Generate Data', "generateDHCPdata('private');", 0); + $cont = addContinuationsEntry('AJgenerateDHCPdata', $this->basecdata); + $h .= " <input type=\"hidden\" id=\"privatedhcpcont\" value=\"$cont\">\n"; + $h .= " </div>\n"; + $h .= " </div>\n"; + + # generate public dhcpd data + $h .= " <div dojoType=\"dijit.PopupMenuItem\">\n"; + $h .= " <span>Generate Public dhcpd Data</span>\n"; + $h .= " <div dojoType=\"dijit.layout.ContentPane\"\n"; + $h .= " style=\"background-color: white; padding: 5px; border: 1px solid black;\">\n"; + $h .= " Select which NIC is used for the Public interface:<br>\n"; + $h .= " <input type=\"radio\" name=\"punic\" value=\"eth0\" id=\"pueth0rdo\">"; + $h .= "<label for=\"eth0rdo\">eth0</label><br>\n"; + $h .= " <input type=\"radio\" name=\"punic\" value=\"eth1\" id=\"pueth1rdo\" "; + $h .= "checked=\"checked\"><label for=\"eth1rdo\">eth1</label><br>\n"; + $h .= dijitButton('', 'Generate Data', "generateDHCPdata('public');", 0); + $h .= " <input type=\"hidden\" id=\"publicdhcpcont\" value=\"$cont\">\n"; # use previous continuation + $h .= " </div>\n"; + $h .= " </div>\n"; + + # generate /etc/hosts data + $h .= " <div dojoType=\"dijit.MenuItem\"\n"; + $h .= " onClick=\"hostsData\">\n"; + $h .= " Generate /etc/hosts Data\n"; + $cont = addContinuationsEntry('AJhostsData', $this->basecdata); + $h .= " <input type=\"hidden\" id=\"hostsdatacont\" value=\"$cont\"><br>\n"; + $h .= " </div>\n"; + + $h .= "</div>\n"; # close Menu + $h .= "</div>\n"; # close DropDownButton + + # computer groups + $tmp = getUserResources(array($this->restype . 'Admin'), array('manageGroup'), 1); + $groups = $tmp[$this->restype]; + $cont = addContinuationsEntry('AJfilterCompGroups', $this->basecdata); + $h .= "<input type=\"hidden\" id=\"filtercompgroupscont\" value=\"$cont\">\n"; + $h .= "<div dojoType=\"dijit.form.DropDownButton\">\n"; + $h .= " <span>Selected Computer Groups</span>\n"; + $h .= " <div dojoType=\"dijit.TooltipDialog\" id=\"connectmethodttd\">\n"; + $size = 10; + if(count($groups) < 10) + $size = count($groups); + $h .= selectInputHTML('', $groups, 'filtercompgroups', + "onChange=\"delayedCompGroupFilterSelection();\" size=\"$size\"", + -1, 0, 1); + $h .= " </div>\n"; # tooltip dialog + $h .= "</div>\n"; # drop down button + + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"confirmactiondlg\"\n"; + $h .= " duration=250\n"; + $h .= " autofocus=false\n"; + $h .= " draggable=true>\n"; + #$h .= "<div id=\"actionmsg\"></div>\n"; + $h .= "<div dojoType=\"dijit.layout.ContentPane\" id=\"actionmsg\"\n"; + $h .= " style=\"background-color: white; padding: 5px;\">\n"; + $h .= "</div>\n"; + $h .= "<div id=\"complist\" style=\"height: 87%; overflow: auto;\"></div>\n"; + $h .= "<input type=\"hidden\" id=\"submitcont\">\n"; + $h .= "<div style=\"text-align: center;\">\n"; + $h .= "<span id=\"submitactionbtnspan\">\n"; + $h .= dijitButton('submitactionbtn', 'Submit', 'submitAction();', 0); + $h .= "</span>\n"; + $h .= dijitButton('cancelactionbtn', 'Cancel', 'cancelAction();', 0); + $h .= "</div>\n"; # btn div + $h .= "</div>\n"; # confirmactiondlg + + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"noschedulenoadd\"\n"; + $h .= " title=\"Cannot Add Computers\"\n"; + $h .= " duration=250\n"; + $h .= " autofocus=false\n"; + $h .= " draggable=true>\n"; + $h .= "All computers must have a schedule assigned to them. You do not<br>\n"; + $h .= "have to any schedules or no schedules exist. You must be granted<br>\n"; + $h .= "access to or create at least one schedule to be able to add computers.<br><br>\n"; + $h .= "<div style=\"text-align: center;\">\n"; + $h .= dijitButton('', 'Close', 'dijit.byId("noschedulenoadd").hide();', 0); + $h .= "</div>\n"; # btn div + $h .= "</div>\n"; # noschedulenoadd + + # filter table + $h .= "<div id=\"extrafiltersdiv\" style=\"height: 65px;\"></div>\n"; + return $h; + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn AJfilterCompGroups + /// + /// \brief generates regular expressions to match ids of all computers in the + /// submitted computer groups + /// + ///////////////////////////////////////////////////////////////////////////// + function AJfilterCompGroups() { + $groupids = processInputVar('groupids', ARG_STRING); + if(! preg_match('/^[0-9,]+$/', $groupids)) { + $ret = array('status' => 'error', + 'errormsg' => "Invalid data submitted."); + sendJSON($ret); + return; + } + $groupids = explode(',', $groupids); + $tmp = getUserResources(array($this->restype . 'Admin'), array('manageGroup'), 1); + $groups = $tmp[$this->restype]; + $groupnames = array(); + foreach($groupids as $id) { + if(array_key_exists($id, $groups)) + $groupnames[] = $groups[$id]; + } + $comps = getResourcesFromGroups($groupnames, 'computer', 1); + $regids = "^" . implode('$|^', array_keys($comps)) . "$"; + $arr = array('status' => 'success', + 'regids' => $regids); + sendJSON($arr); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn addEditDialogHTML($add) + /// + /// \param $add - unused for this class + /// + /// \brief generates HTML for dialog used to edit resource + /// + ///////////////////////////////////////////////////////////////////////////// + function addEditDialogHTML($add) { + global $user; + # dialog for on page editing + $h = ''; + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"addeditdlg\"\n"; + $h .= " title=\"Edit {$this->restypename}\"\n"; + $h .= " duration=250\n"; + $h .= " draggable=true>\n"; + $h .= "<div id=\"addeditdlgcontent\">\n"; + $h .= "<div id=\"computerdlgcontent\">\n"; + # id + $h .= "<input type=\"hidden\" id=\"editresid\">\n"; + + $types = array("blade" => "Bare Metal", "lab" => "Lab", "virtualmachine" => "Virtual Machine"); + $provisioning = getProvisioning(); + $provtypes = getProvisioningTypes(); + $states = array('blade' => array(2 => 'available', + 10 => 'maintenance', + 20 => 'vmhostinuse'), + 'lab' => array(2 => 'available', + 10 => 'maintenance'), + 'virtualmachine' => array(10 => 'maintenance')); + + $h .= "<script type=\"text/javascript\">\n"; + $h .= "var options = {\n"; + $options = array(); + foreach($types as $type => $tmp) { + $opt = ''; + $opt .= " $type: {\n"; + $opt .= " provisioning: [\n"; + $arr = array(); + foreach($provtypes[$type] as $key => $val) + $arr[] = " {value: '$key', label: '$val'}"; + $opt .= implode(",\n", $arr); + $opt .= "\n ],\n"; + $opt .= " states: [\n"; + $arr = array(); + foreach($states[$type] as $key => $val) + $arr[] = " {value: '$key', label: '$val'}"; + $opt .= implode(",\n", $arr); + $opt .= "\n ]\n"; + $opt .= " }"; + $options[] = $opt; + } + $h .= implode(",\n", $options); + $h .= "\n}\n"; + $h .= "</script>\n"; + + # add single or multiple + $h .= "<div id=\"singlemultiplediv\" class=\"hidden\">\n"; + /*$h .= "<label for=\"addsingle\">Add Single Computer</label><span "; + $h .= "class=\"labeledform\"><input type=\"radio\" name=\"mode\" "; + $h .= "id=\"addsingle\" checked=\"checked\" onclick=\"toggleAddSingle();\">"; + $h .= "</span><br><br>\n"; + $h .= "<label for=\"addmultiple\">Add Multiple Computers</label><span "; + $h .= "class=\"labeledform\"><input type=\"radio\" name=\"mode\" "; + $h .= "id=\"addmultiple\" onclick=\"toggleAddMultiple();\"><br><br>\n";*/ + $extra = array('onChange' => 'toggleSingleMultiple();'); + $modes = array('single' => 'Single Computer', + 'multiple' => 'Multiple Computers'); + $h .= labeledFormItem('mode', 'Add ', 'select', $modes, 1, '', '', '', $extra); + $h .= "<br>\n"; + $h .= "</div>\n"; # singlemultiplediv + + # add multiple note + $h .= "<div id=\"multiplenotediv\" class=\"hidden\">\n"; + $h .= "<b>NOTE</b>: 'Start IP' and 'End IP' can only differ in the number "; + $h .= "after the last '.'. The<br>hostnames will be generated from the "; + $h .= "'Hostname' field. The hostnames for each<br>computer can only differ "; + $h .= "by the value of a number in the first part of the hostname.<br>Place "; + $h .= "a '%' character in the 'Hostname' field where that number will be. "; + $h .= "Then fill in<br>'Start value' and 'End value' with the first and last "; + $h .= "values to be used in the hostname.<br><br>"; + $h .= "</div>\n"; # multiplenotediv + + # div for canceling moving blade to vmhostinuse + $h .= "<div class=\"highlightnoticewarn hidden\" id=\"cancelvmhostinusediv\">\n"; + $h .= "<span id=\"tohostfuturespan\">\n"; + $h .= "NOTICE: This computer is scheduled to start being reloaded as a vmhost at<br>"; + $h .= "<span id=\"tohostfuturetimespan\"></span>"; + $h .= ". You may cancel this scheduled<br>reload by clicking the button below."; + $h .= "<br><br></span>\n"; + $h .= "<span id=\"tohostnowspan\">\n"; + $h .= "NOTICE: This computer is currently being reloaded as a vmhost. You may cancel this<br>"; + $h .= "process by clicking on the button below. After canceling the reload, it may take several<br>"; + $h .= "minutes for the cancellation process to complete."; + $h .= "<br><br></span>\n"; + $h .= "<input type=\"hidden\" id=\"tohostcancelcont\">\n"; + $h .= "<button dojoType=\"dijit.form.Button\">\n"; + $h .= " Cancel Scheduled Reload\n"; + $h .= " <script type=\"dojo/method\" event=onClick>\n"; + $h .= " cancelScheduledtovmhostinuse();\n"; + $h .= " </script>\n"; + $h .= "</button>\n"; + $h .= "</div>\n"; # cancelvmhostinusediv + $h .= "<div class=\"highlightnoticenotify hidden\" id=\"cancelvmhostinuseokdiv\"></div>\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 .= "<div id=\"startenddiv\" class=\"hidden\">\n"; + $extra = array('smallDelta' => 1, 'largeDelta' => 10); + $h .= labeledFormItem('startnum', 'Start*', 'spinner', '{min:0,max:255,places:0}', 1); + $h .= labeledFormItem('endnum', 'End*', 'spinner', '{min:0,max:255,places:0}', 1); + $h .= "</div>\n"; # startenddiv + + # owner + $extra = array('onKeyPress' => 'setOwnerChecking'); + $h .= labeledFormItem('owner', 'Owner*', 'text', '', 1, + "{$user['unityid']}@{$user['affiliation']}", 'Unknown user', + 'checkOwner', $extra); + $cont = addContinuationsEntry('AJvalidateUserid'); + $h .= "<input type=\"hidden\" id=\"valuseridcont\" value=\"$cont\">\n"; + + # type + $extra = array('onChange' => 'selectType();'); + $h .= labeledFormItem('type', 'Type', 'select', $types, 1, '', '', '', $extra); + + # single computer fields + $h .= "<div id=\"singleipmacdiv\">\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 .= "</div>\n"; # singleipmacdiv + + # multi computer fields + $h .= "<div id=\"multiipmacdiv\" class=\"hidden\">\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 .= "</div>\n"; # multiipsdiv + + # provisioning engine + $extra = array('onChange' => 'selectProvisioning();'); + $h .= labeledFormItem('provisioningid', 'Provisioning Engine', 'selectonly', $provisioning, 1, '', '', '', $extra); + + # state + $extra = array('onChange' => 'selectState();'); + $states = array(2 => 'available', + 23 => 'hpc', + 10 => 'maintenance', + 20 => 'vmhostinuse'); + $h .= labeledFormItem('stateid', 'State', 'selectonly', $states, 1, '', '', '', $extra); + + # maintenance notes + $h .= "<div id=\"notesspan\">\n"; + $h .= labeledFormItem('notes', 'Reason for maintenance', 'textarea'); + $h .= "</div>\n"; + + # VMhost profile + $profiles = getVMProfiles(); + uasort($profiles, 'sortKeepIndex'); + $h .= "<div id=\"vmprofilespan\">\n"; + $h .= labeledFormItem('vmprofileid', 'VM Host Porfile', 'select', $profiles); + $h .= "</div>\n"; + + # platform + $platforms = getPlatforms(); + $h .= labeledFormItem('platformid', 'Platform', 'select', $platforms); + + # schedule + $tmp = getUserResources(array("scheduleAdmin"), array("manageGroup")); + $schedules = $tmp["schedule"]; + $h .= labeledFormItem('scheduleid', 'Schedule', 'select', $schedules); + + # current image + $h .= "<div id=\"curimgspan\">\n"; + $h .= "<label for=\"curimg\">Current Image:</label>\n"; + $h .= "<span class=\"labeledform\" id=\"curimg\"></span><br>\n"; + $h .= "</div>\n"; + + # ram + $extra = array('smallDelta' => 1024, 'largeDelta' => 4096); + $h .= labeledFormItem('ram', 'RAM (MB)*', 'spinner', '{min:500,max:16777215,places:0}', 1); + + # cores + $extra = array('smallDelta' => 1, 'largeDelta' => 4); + $h .= labeledFormItem('cores', 'No. Cores*', 'spinner', '{min:1,max:255,places:0}', 1); + + # proc speed + $extra = array('smallDelta' => 100, 'largeDelta' => 1000); + $h .= labeledFormItem('procspeed', 'Processor Speed (MHz)*', 'spinner', '{min:500,max:10000,places:0}', 1); + + # network speed + $tmpArr = array("10" => "10", "100" => "100", "1000" => "1000", "10000" => "10000", "100000" => "100000"); + $h .= labeledFormItem('network', 'Network', 'select', $tmpArr); + + # compid + $h .= "<div id=\"compidspan\">\n"; + $h .= "<label for=\"compid\">Computer ID:</label>\n"; + $h .= "<span class=\"labeledform\" id=\"compid\"></span><br>\n"; + $h .= "</div>\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 .= "</div>\n"; # computerdlgcontent + $h .= "</div>\n"; # addeditdlgcontent + + $h .= "<div id=\"addeditdlgerrmsg\" class=\"nperrormsg\"></div>\n"; + + $h .= "<div id=\"editdlgbtns\" align=\"center\">\n"; + $h .= dijitButton('addeditbtn', "Confirm", "saveResource();"); + $h .= dijitButton('', "Cancel", "dijit.byId('addeditdlg').hide();"); + $h .= "</div>\n"; # editdlgbtns + $h .= "</div>\n"; # dialog + + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"groupingnote\"\n"; + $h .= " title=\"Computer Grouping\"\n"; + $h .= " duration=250\n"; + $h .= " draggable=true>\n"; + $h .= "Computer(s) successfully added. Each computer needs<br>to be a member of a computer resource group. The<br>following dialog<br>will allow you to add the new<br>computer(s) to a group.<br><br>\n"; + $h .= "<div align=\"center\">\n"; + $h .= dijitButton('', "Close", "dijit.byId('groupingnote').hide();"); + $h .= "</div>\n"; # btn div + $h .= "</div>\n"; # groupingnote + + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"groupdlg\"\n"; + $h .= " title=\"Computer Grouping\"\n"; + $h .= " duration=250\n"; + $h .= " draggable=true>\n"; + $h .= "<div id=\"groupdlgcontent\"></div>\n"; + $h .= "<div align=\"center\">\n"; + $script = " dijit.byId('groupdlg').hide();\n"; + $script .= " checkFirstAdd();\n"; + $h .= dijitButton('', "Close", $script); + $h .= "</div>\n"; # btn div + $h .= "</div>\n"; # groupdlg + return $h; + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn AJeditResource() + /// + /// \brief sends data for editing a resource + /// + ///////////////////////////////////////////////////////////////////////////// + function AJeditResource() { + $rscid = processInputVar('rscid', ARG_NUMERIC); + $resources = getUserResources(array($this->restype . 'Admin'), array('administer'), 0, 1); + if(! array_key_exists($rscid, $resources[$this->restype])) { + $ret = array('status' => 'noaccess'); + sendJSON($ret); + return; + } + $this->jsondata['showcancel'] = 0; + $query = "SELECT UNIX_TIMESTAMP(rq.start) AS start " + . "FROM request rq, " + . "reservation rs, " + . "state ls, " + . "state cs " + . "WHERE rs.requestid = rq.id AND " + . "rs.computerid = $rscid 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 " + . "LIMIT 1"; + $qh = doQuery($query); + if($row = mysql_fetch_assoc($qh)) { + $cdata = $this->basecdata; + $cdata['compid'] = $rscid; + $cont = addContinuationsEntry('AJcanceltovmhostinuse', $cdata, 300, 1, 0); + $this->jsondata['tohostcancelcont'] = $cont; + $this->jsondata['showcancel'] = 1; + $this->jsondata['tohoststart'] = date('g:i A \o\n l, F jS, Y', $row['start']); + if($row['start'] > time()) + $this->jsondata['tohostfuture'] = 1; + else + $this->jsondata['tohostfuture'] = 0; + } + parent::AJeditResource(); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn AJsaveResource() + /// + /// \brief saves changes to resource + /// + ///////////////////////////////////////////////////////////////////////////// + function AJsaveResource() { + global $user; + $add = getContinuationVar('add', 0); + $data = $this->validateResourceData(); + if($data['error']) { + $ret = array('status' => 'error', 'msg' => $data['errormsg']); + sendJSON($ret); + return; + } + + $promptuser = 0; + $promptuserfail = 0; + $multirefresh = 0; + + if($add) { + if(! $data['rscid'] = $this->addResource($data)) { + sendJSON(array('status' => 'adderror', + 'errormsg' => 'Error encountered while trying to create new computer(s).<br>Please contact an admin for assistance.')); + return; + } + } + else { + $olddata = getContinuationVar('olddata'); + $updates = array(); + # hostname + if($data['name'] != $olddata['hostname']) + $updates[] = "hostname = '{$data['name']}'"; + + # ownerid + $ownerid = getUserlistID($data['owner']); + if($ownerid != $olddata['ownerid']) + $updates[] = "ownerid = $ownerid"; + + # cores + if($data['cores'] != $olddata['procnumber']) + $updates[] = "procnumber = '{$data['cores']}'"; + + # eth0macaddress + if($data['eth0macaddress'] != $olddata['eth0macaddress']) { + if($data['eth0macaddress'] == '') + $updates[] = "eth0macaddress = NULL"; + else + $updates[] = "eth0macaddress = '{$data['eth0macaddress']}'"; + } + + # eth1macaddress + if($data['eth1macaddress'] != $olddata['eth1macaddress']) { + if($data['eth1macaddress'] == '') + $updates[] = "eth1macaddress = NULL"; + else + $updates[] = "eth1macaddress = '{$data['eth1macaddress']}'"; + } + + # other fields + $fields = array('type', 'IPaddress', 'privateIPaddress', + 'provisioningid', 'platformid', 'scheduleid', 'ram', + 'procspeed', 'network', 'location'); + foreach($fields as $field) { + if($data[$field] != $olddata[$field]) + $updates[] = "`$field` = '{$data[$field]}'"; + } + + # notes + # 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 moving from vmhostinuse or reloading with a new image, + # make sure no reservations for VMs + if($olddata['stateid'] == 10 && $data['stateid'] == 20) { + $query = "SELECT vm.id " + . "FROM computer vm, " + . "vmhost v " + . "WHERE v.computerid = {$data['rscid']} AND " + . "vm.vmhostid = v.id AND " + . "vm.notes = 'maintenance with host {$data['rscid']}' AND " + . "vm.stateid = 10"; + $qh = doQuery($query); + $vmids = array(); + while($row = mysql_fetch_assoc($qh)) + $vmids[] = $row['id']; + $allids = implode(',', $vmids); + if($data['provisioning'] != 'none') { + $profiles = getVMProfiles(); + if(! array_key_exists('vmprofileid', $olddata) || + $olddata['vmprofileid'] == '' || + $profiles[$olddata['vmprofileid']]['imageid'] != + $profiles[$data['vmprofileid']]['imageid']) { + # VCL provisioned, different image + # schedule VM host to be reloaded + $profiles = getVMProfiles($data['vmprofileid']); + $imageid = $profiles[$data['vmprofileid']]['imageid']; + $start = getReloadStartTime(); + $rc = $this->scheduleTovmhostinuse($data['rscid'], $imageid, $start, + $data['vmprofileid'], $olddata['vmprofileid']); + + if($rc == 0) { + $msg = ''; + if(count($updates)) + $msg .= "Computer information changes were saved.<br>\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<br>', $msg); + $promptuserfail = 1; + $title = 'VM Host Reload Failed'; + } + else { + if(count($vmids)) + $this->scheduleVMsToAvailable($vmids); + $multirefresh = 3; + } + } + else { + # VCL provisioned, same image + $msg = ''; + if(count($updates)) + $msg .= "Computer information changes saved.<br><br>\nHowever, this "; + else + $msg .= "This "; + $msg .= "computer was previously in the vmhostinuse state. "; + $msg .= "You can:<br><br>\n"; + $msg .= "<input type=\"radio\" name=\"mode\" value=\"vmhostinuse\" "; + $msg .= "id=\"modedirect\" checked=\"checked\"><label "; + $msg .= "for=\"modereload\">Move it directly back to vmhostinuse\n"; + $msg .= "</label><br>\n"; + $msg .= "<input type=\"radio\" name=\"mode\" value=\"reload\" "; + $msg .= "id=\"modereload\"><label for=\"modereload\">Have it reloaded "; + $msg .= "and then placed back into vmhostinuse</label><br><br>\n"; + $promptuser = 1; + $cdata = $this->basecdata; + $cdata['compid'] = $data['rscid']; + $cdata['imageid'] = $profiles[$data['vmprofileid']]['imageid']; + $cdata['oldprofileid'] = $olddata['vmprofileid']; + $cdata['vmprofileid'] = $data['vmprofileid']; + $cdata['newstateid'] = $data['stateid']; + $cdata['oldstateid'] = $olddata['stateid']; + $cdata['vmids'] = $vmids; + $promptcont = addContinuationsEntry('AJsubmitComputerStateLater', $cdata, SECINDAY, 1, 0); + $btntxt = 'Submit'; + $title = 'State Change Option'; + } + $data['stateid'] = $olddata['stateid']; # prevent state from being updated directly + } + elseif(count($vmids)) { + $query = "UPDATE computer " + . "SET stateid = 2, " + . "notes = '' " + . "WHERE id in ($allids)"; + doQuery($query); + $multirefresh = 1; + } + } + elseif($olddata['stateid'] != 20 && $data['stateid'] == 20) { + # check for reservations + moveReservationsOffComputer($data['rscid']); + cleanSemaphore(); + $reloadstart = getCompFinalReservationTime($data['rscid'], 21); + $checkstart = getExistingChangeStateStartTime($data['rscid'], 21); + if($data['provisioning'] != 'none') { + # VCL provisioned + $profiles = getVMProfiles($data['vmprofileid']); + $imageid = $profiles[$data['vmprofileid']]['imageid']; + if($reloadstart) { + if($checkstart && $checkstart < $reloadstart) + $reloadstart = $checkstart; + # reservations, must wait until end time + $end = date('n/j/y g:i a', $reloadstart); + $msg = ''; + if(count($updates)) + $msg .= "Computer information changes saved.<br>\nHowever, this "; + else + $msg .= "This "; + $msg .= "computer is currently allocated until $end and cannot "; + $msg .= "be reloaded until then. You can:\n"; + $msg .= "<ul><li>Cancel and try later</li>\n"; + $msg .= "<li>Schedule the computer to be reloaded with the selected "; + $msg .= "profile at $end</li></ul>\n"; + $msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg); + $msg = preg_replace("|$end|", "<strong>$end</strong>", $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.<br>\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<br>', $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.<br>\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 .= "<ul><li>Cancel and do nothing</li>\n"; + $msg .= "<li>Schedule the computer to go in to maintenance at $end "; + $msg .= "and manually move it to vmhostinuse after that</li></ul>\n"; + $msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg); + $msg = preg_replace("|$end|", "<strong>$end</strong>", $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.<br>\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<br>', $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.<br>\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 .= "<ul><li>Cancel and do nothing</li>\n"; + $msg .= "<li>Schedule the VMs to be removed at $end and the computer "; + $msg .= "to be moved to available that</li></ul>\n"; + $msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg); + $msg = preg_replace("|$end|", "<strong>$end</strong>", $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.<br>\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<br>', $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.<br>\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<br>', $msg); + $promptuserfail = 1; + $title = 'Change to Maintenance Failed'; + } + elseif($reloadstart > 0) { + cleanSemaphore(); + $end = date('n/j/y g:i a', $reloadstart); + $msg = ''; + if(count($updates)) + $msg .= "Computer information changes saved.<br>\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 .= "<ul><li>Cancel and do nothing</li>\n"; + $msg .= "<li>Schedule the computer and VMs to be moved into the "; + $msg .= "maintenance state at $end</li></ul>\n"; + $msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg); + $msg = preg_replace("|$end|", "<strong>$end</strong>", $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.<br>\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<br>', $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.<br>\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 .= "<ul><li>Cancel and do nothing</li>\n"; + $msg .= "<li>Schedule the VMs to be removed and the computer to be "; + $msg .= "reloaded at $end</li></ul>\n"; + $msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg); + $msg = preg_replace("|$end|", "<strong>$end</strong>", $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.<br>\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<br>', $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.<br>\nHowever, this "; + else + $msg .= "This "; + $msg .= "computer has reservations on it until $end. You can:\n"; + $msg .= "<ul><li>Cancel and do nothing</li>\n"; + $msg .= "<li>Schedule the computer to be moved to maintenance at "; + $msg .= "$end</li></ul>\n"; + $msg = preg_replace("/(.{1,76}([ \n]|$))/", '\1<br>', $msg); + $msg = preg_replace("|$end|", "<strong>$end</strong>", $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 + } + + # 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)); + unset($_SESSION['userresources'][$key]); + $key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 0, 0)); + unset($_SESSION['userresources'][$key]); + $key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 0, 1, 0)); + unset($_SESSION['userresources'][$key]); + $key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 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.<br><br>"; + $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 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['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['stateid'] != $olddata['stateid']) { + $return['error'] = 1; + $errormsg[] = "Invalid value submitted for State"; + } + # validate type/provisioning combinations + $provtypes = getProvisioningTypes(); + if($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($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 && + (! 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<br>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"; + } + # 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('<br>', $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'); + 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']}'"); + + $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); + } + + // add entry in resource table + $query = "INSERT INTO resource " + . "(resourcetypeid, " + . "subid) " + . "VALUES (12, " + . "$rscid)"; + 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']}'"); + + $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); + } + + // 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<br>', $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) {
[... 2117 lines stripped ...]
