Last active
August 29, 2015 14:16
-
-
Save djtecha/63565ceb398334ea19af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* Facter (Puppet) plugin for racktables 0.20.1 (and probably newer) | |
* | |
* This file is both a web GUI and REST webservice for auto create and update machines based on facter (puppet) files. | |
* | |
* REST example: | |
* curl -F "userfile=@/root/facter.txt" -u username:password "http://racktables/index.php?module=redirect&page=depot&tab=facter&op=Update" | |
* | |
* Usage instructions: | |
* Add to plugins folder along with manifest file | |
* To get VMs to auto add you have to create a facter function to return a list like: | |
* export FACTER_VMs=$(virsh list | awk '$3 == "running" {printf $2","}' | sed -e 's/,$//'); | |
* Whatever you use for VMs it should return a list like: vms => vm1,vm2 | |
* | |
* | |
* Author: Torstein Hansen <[email protected]>, sponsored by eniro.no | |
* | |
* This script is based on yaml_import for racktables by Tommy Botten Jensen | |
* | |
* 2011-08-25 modified by Neil Scholten <[email protected]> | |
* - adjusted path for racktables > 0.19.1 | |
* - modified .yaml parsing to match to 'facter -py' format | |
* - modified interface-type detection to use virtual port on VMs | |
* - modified OS detection to match more better default sets (Testcase: CentOS). | |
* | |
* 2012-12-13 modified by Daniel Kasen <[email protected]> | |
* - added generic looping to easially add fields | |
* - Corrected issues with VM's breaking script | |
* - reverted .yaml parsing due to strings in facter not parsing right for mem. options | |
* - added error checking to ignore unusable lines in manifest file | |
* - fixed ip additions for 20.1 | |
* - added VM auto adding to Parent | |
* | |
* 2015-02-10 modified by Gjermund Jensvoll <[email protected]> | |
* - RackTables >= 0.20.8 compatability (Fixing error "Argument 'port_type_id' of value NULL is invalid (format error)") | |
* | |
*/ | |
// Depot Tab for objects. | |
$tab['depot']['facter'] = 'Facter'; | |
$tabhandler['depot']['facter'] = 'ViewHTML'; | |
$ophandler['depot']['facter']['Update'] = 'Update'; | |
// The ophandler to insert objects (if any) | |
function Update() | |
{ | |
// Read uploaded file | |
$lines = file($_FILES['userfile']['tmp_name']); | |
// add file contents to facter array | |
foreach ($lines as $line_num => $line) | |
{ | |
$tmpfacter=explode("=>",$line,2); | |
$facter[trim($tmpfacter[0])]=str_replace('"', '',trim($tmpfacter[1])); | |
} | |
// Fix fqdn since all fields have \n inn them | |
$facter['fqdn']=str_replace("\n","", $facter['fqdn']); | |
// Check if it's an existing machine | |
// 2011-08-31 <[email protected]> | |
// * expanded query to try to match via facter Serialnumber to be able to | |
// match unnamed HW assets. Serial is more precise and less likely to be changed. | |
if ( | |
array_key_exists('serialnumber', $facter) && | |
strlen($facter['serialnumber']) > 0 && | |
$facter['serialnumber'] != 'Not Specified' ) { | |
$FQDN = $facter[fqdn]; | |
$SERIAL = $facter[serialnumber]; | |
$query = "select id from RackObject where name REGEXP '^ *$FQDN' OR asset_no REGEXP '^ *$SERIAL' LIMIT 1"; | |
} else { | |
$FQDN = $facter[fqdn]; | |
$query = "select id from RackObject where name REGEXP '^ *$FQDN' LIMIT 1"; | |
} | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$id=$resultarray[0]['id']; | |
} | |
// If it's a new machine | |
if (! isset($id)) | |
{ | |
// Check to see if it's a physical machine and get the correct id for Server | |
if ($facter['is_virtual']=="false") | |
{ | |
// Find server id | |
$query = "select dict_key from Dictionary where dict_value='Server' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (); | |
if($resultarray) | |
{ | |
$virtual=$resultarray[0]['dict_key']; | |
} | |
} | |
// Check to see if it's a virtual machine and get the correct id for VM | |
else | |
{ | |
// Find virtual id | |
$query = "select dict_key from Dictionary where dict_value='VM' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) | |
{ | |
$virtual=$resultarray[0]['dict_key']; | |
} | |
} | |
// Add the new machine | |
$newmachine=commitAddObject($facter['fqdn'],"",$virtual,$value = ""); | |
$type_id = getObjectTypeID($newmachine); | |
} | |
// If it's an existing machine | |
else | |
{ | |
// Just set some fields I use later down for updating | |
$newmachine=$id; | |
$machineupdate=1; | |
$type_id = getObjectTypeID($newmachine); | |
} | |
if ( | |
array_key_exists('serialnumber', $facter) && | |
strlen($facter['serialnumber']) > 0 && | |
$facter['serialnumber'] != 'Not Specified' ) { | |
$SERIAL = $facter[serialnumber]; | |
unset($result); | |
$query = "select * from RackObject where asset_no REGEXP '^ *$SERIAL' LIMIT 1"; | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$id = $resultarray[0]['id']; | |
$label = $resultarray[0]['label']; | |
commitUpdateObject($id, $facter['fqdn'], $label, 'no', $facter['serialnumber'], 'Facter Import::Update Common Name'); | |
} | |
} | |
if ($facter['is_virtual']=="false") | |
{ | |
$iHWTemp = preg_match('([a-zA-Z]{1,})', $facter['manufacturer'], $matches); | |
$sManufacturer = $matches[0]; | |
$sHW = preg_replace('(\ )', '\1%GPASS%', $facter['productname']); | |
$sHWType = $sManufacturer.' '.$sHW; | |
$query = "select id from Attribute where name REGEXP '^ *HW type$' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$id=$resultarray[0]['id']; | |
$hw_dict_key = getdict($sHWType, $chapter=11 ); | |
commitUpdateAttrValue ($object_id = $newmachine, $attr_id = $id, $value = $hw_dict_key); | |
} | |
//Also Check if HYPERVISOR | |
if (isset($facter['hypervisor_type'])) | |
{ | |
$query = "select id from Attribute where name REGEXP '^ *Hypervisor Type$' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$id=$resultarray[0]['id']; | |
$hypervisor_type = $facter['hypervisor_type']; | |
$hypervisor_type_dict_key = getdict($hw=$hypervisor_type, $chapter=10005); | |
commitUpdateAttrValue ($object_id = $newmachine, $attr_id = $id, $value = $hypervisor_type_dict_key); | |
} | |
//Set Value to Yes | |
$query = "select id from Attribute where name REGEXP '^ *Hypervisor' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$id=$resultarray[0]['id']; | |
$hypervisor = "Yes"; | |
$hypervisor_dict_key = getdict($hypervisor, $chapter=29); | |
commitUpdateAttrValue ($object_id = $newmachine, $attr_id = $id, $value = $hypervisor_dict_key); | |
} | |
//Find Running VMs | |
$vms = explode(',',$facter['vms']); | |
$vm_count = count($vms); | |
for ($i = 0; $i < $vm_count; $i++) { | |
//addToParent | |
addVmToParent ($vms[$i], $newmachine); | |
} | |
} else { | |
$query = "select id from Attribute where name REGEXP '^ *Hypervisor' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$id=$resultarray[0]['id']; | |
// Update Hypervisor type | |
$hypervisor = "No"; | |
$hypervisor_dict_key = getdict($hypervisor, $chapter=29); | |
commitUpdateAttrValue ($object_id = $newmachine, $attr_id = $id, $value = ""); | |
} | |
} | |
} | |
// Find SW type id (OS) | |
$query = "select id from Attribute where name REGEXP '^ *SW type$' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$id=$resultarray[0]['id']; | |
// Update SW type (OS) | |
$osrelease = $facter['operatingsystem'] . '%GSKIP%' . $facter['operatingsystem'] . ' V' . $facter['operatingsystemrelease']; | |
$os_dict_key = getdict($hw=$osrelease, $chapter=13); | |
commitUpdateAttrValue ($object_id = $newmachine, $attr_id = $id, $value = $os_dict_key); | |
} | |
//Generic to read in from file | |
$manifest_file = fopen("../plugins/manifest", "r") or die("Could not open manifest, make sure it is in the websrv root and called manifest \n"); | |
while ( ! feof ($manifest_file)) { | |
$tmp_line = fgets($manifest_file); | |
if (!empty($tmp_line) && !preg_match("/\/\//",$tmp_line)) { | |
@list($Fact, $Attr, $Chapter) = array_map('trim', (explode(',', $tmp_line, 3))); | |
//check for multi-facter names | |
if(strstr($Fact, '.')) { | |
@list($Fact1, $Fact2) = array_map('trim', (explode('.', $Fact))); | |
$value = $facter[$Fact1] .' '. $facter[$Fact2]; | |
if(!isset($facter[$Fact1]) || !isset($facter[$Fact2])) { | |
echo "WARNING: $Fact1 or $Fact2 does not exist in Facter for this object \n"; | |
continue; | |
} | |
} else { | |
if(!isset($facter[$Fact])) { | |
echo "WARNING: $Fact does not exist in Facter for this object \n"; | |
continue; | |
} else { | |
$value = $facter[$Fact]; | |
} | |
} | |
$query = "select id from Attribute where name REGEXP '^ *$Attr' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
$id=$resultarray[0]['id']; | |
if (!valid($type_id, $id)) { | |
echo "WARNING: Not a valid Mapping for $Fact to $Attr for objectType $type_id \n"; | |
} | |
else if($resultarray) { | |
if (preg_match("/[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}/",$value) || preg_match("/[0-9]{1,2}\-[0-9]{1,2}\-[0-9]{4}/",$value) || preg_match("/[0-9]{4}\-[0-9]{1,2}\-[0-9]{1,2}/",$value)) { | |
commitUpdateAttrValue ($newmachine, $id, strtotime($value) ); | |
} else { | |
$chapter_id = getdictid($Attr); | |
if (!empty($chapter_id)) | |
$value = getdict($value, $chapter_id); | |
commitUpdateAttrValue ($newmachine, $id, $value); | |
} | |
} | |
} | |
} | |
fclose($manifest_file); | |
// Add network interfaces | |
// Create an array with interfaces | |
$nics = explode(',',$facter['interfaces']); | |
//Check for iDrac or Ec2 External | |
if (isset($facter['idrac'])) | |
$nics[] = "idrac"; | |
if (isset($facter['ipaddress_external'])) | |
$nics[] = "external"; | |
// Go through all interfaces and add IP and MAC | |
$count = count($nics); | |
for ($i = 0; $i < $count; $i++) { | |
// Remove newline from the field | |
$nics[$i]=str_replace("\n","", $nics[$i]); | |
// We generally don't monitor sit interfaces. | |
// We don't do this for lo interfaces, too | |
// 2011-08-31 <[email protected]> | |
// * Only Document real interfaces, dont do bridges, bonds, vlan-interfaces | |
// when they have no IP defined. | |
if ( preg_match('(_|^(bond|lo|sit|vnet|virbr|veth|peth))',$nics[$i]) != 0 ) { | |
// do nothing | |
} else { | |
// Get IP | |
if (isset($facter['ipaddress_' . $nics[$i]])) | |
$ip = $facter['ipaddress_' . $nics[$i]]; | |
// Get MAC | |
if (isset($facter['macaddress_' . $nics[$i]])) | |
$mac = $facter['macaddress_' . $nics[$i]]; | |
//check if VM or not | |
if ($facter['is_virtual']=="false") | |
{ | |
// Find 1000Base-T id | |
$query = "select id from PortOuterInterface where oif_name REGEXP '^ *1000Base-T$' LIMIT 1"; | |
} | |
else | |
{ | |
// Find virtual port id | |
$query = "select id from PortOuterInterface where oif_name REGEXP '^ *virtual port$' LIMIT 1"; | |
} | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$nictypeid=$resultarray[0]['id']; | |
} | |
// Remove newline from ip | |
$ip=str_replace("\n","", $ip); | |
// Check to se if the interface has an ip assigned | |
$query = "SELECT object_id FROM IPv4Allocation where object_id=$newmachine and name=\"$nics[$i]\""; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
unset($id); | |
$ipcheck=$resultarray; | |
} | |
// Check if it's been configured a port already | |
$query = "SELECT id,iif_id FROM Port where object_id=$newmachine and name=\"$nics[$i]\""; | |
unset($result); | |
$result = usePreparedSelectBlade ($query); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($resultarray) { | |
$portid = $resultarray[0]['id']; | |
unset($id); | |
$portcheck=$resultarray; | |
} | |
// Add/update port | |
// 2011-08-31 <[email protected]> | |
// * Don't touch already existing complex ports | |
if ( $resultarray[0]['type'] != 9 ) { | |
if ( count($portcheck) == 1 ) { | |
commitUpdatePort($newmachine,$portid, $nics[$i], $nictypeid, "Ethernet port", "$mac", NULL); | |
} | |
else | |
{ | |
commitAddPort($object_id = $newmachine, $nics[$i], $nictypeid,'Ethernet port',"$mac"); | |
} | |
} else { | |
//We've got a complex port, don't touch it, it raises an error with 'Database error: foreign key violation' | |
} | |
if (count($ipcheck) == 1 ) { | |
if( $ip ) { | |
updateAddress(ip_parse($ip) , $newmachine, $nics[$i],'regular'); | |
} | |
} | |
else | |
{ | |
if( $ip ) { | |
bindIpToObject(ip_parse($ip), $newmachine, $nics[$i],'regular'); | |
} | |
} | |
unset($portcheck); | |
unset($ipcheck); | |
unset($ip); | |
unset($mac); | |
} | |
} | |
addTagToObject($facter, $newmachine); | |
return buildRedirectURL (); | |
} | |
// Display the import page. | |
function ViewHTML() | |
{ | |
startPortlet(); | |
echo "<table with=90% align=center border=0 cellpadding=5 cellspacing=0 align=center class=cooltable><tr valign=top>"; | |
echo "<form method=post enctype=\"multipart/form-data\" action='index.php?module=redirect&page=depot&tab=facter&op=Update'>"; | |
echo "<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"30000\" />"; | |
echo "Upload a facter file: <input name=\"userfile\" type=\"file\" /><br />"; | |
echo "<input type=\"submit\" value=\"Upload File\" />"; | |
echo "</td></tr></table></td></tr>"; | |
echo "</form>"; | |
echo "</table>"; | |
finishPortlet(); | |
} | |
function getdict ($hw,$chapter) { | |
try { | |
global $dbxlink; | |
$query = "select dict_key from Dictionary where chapter_id='$chapter' AND dict_value ='$hw' LIMIT 1"; | |
$result = usePreparedSelectBlade ($query); | |
$array = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($array) { | |
return $array[0]['dict_key']; | |
} | |
else { | |
$dbxlink->exec("INSERT INTO Dictionary (chapter_id,dict_value) VALUES ('$chapter','$hw')"); | |
$squery = "select dict_key from Dictionary where dict_value ='$hw' AND chapter_ID ='$chapter' LIMIT 1"; | |
$sresult = usePreparedSelectBlade ($squery); | |
$sarray = $sresult->fetchAll (PDO::FETCH_ASSOC); | |
if($sarray) { | |
return $sarray[0]['dict_key']; | |
} | |
else { | |
return 0; | |
} | |
} | |
$dbxlink = null; | |
} | |
catch(PDOException $e) | |
{ | |
echo $e->getMessage(); | |
} | |
} | |
function getdictid ($attribute) { | |
$query = "select id from Attribute WHERE name REGEXP '^ *$attribute$' AND type = 'dict'"; | |
$result = usePreparedSelectBlade ($query); | |
$array = $result->fetchAll (PDO::FETCH_ASSOC); | |
if($array) { | |
$attr_id = $array[0]['id']; | |
$query = "select chapter_id from AttributeMap WHERE attr_id = '$attr_id' LIMIT 1"; | |
$result = usePreparedSelectBlade ($query); | |
$array = $result->fetchAll (PDO::FETCH_ASSOC); | |
return $array[0]['chapter_id']; | |
} | |
else | |
return 0; | |
} | |
//new check to make sure the object type allows the string | |
function valid ($type_id, $id) { | |
//Check to see if this combination exists in the AttributeMap | |
$valid = "SELECT * from AttributeMap WHERE objtype_id = '$type_id' AND attr_id = '$id' LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($valid); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
$exists = $resultarray[0]['objtype_id']; | |
if (!empty($exists)) | |
return 1; | |
else | |
return 0; | |
} | |
function getObjectTypeID ($newmachine) { | |
$objtype = "SELECT objtype_id from RackObject WHERE id = $newmachine LIMIT 1"; | |
unset($result); | |
$result = usePreparedSelectBlade ($objtype); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
return $resultarray[0]['objtype_id']; | |
} | |
//Find Parent of VM Object | |
function addVmToParent ($vms, $newmachine) { | |
$search_for_child = "select id from RackObject WHERE name REGEXP '^ *$vms\\\.'"; | |
unset($result); | |
$result = usePreparedSelectBlade ($search_for_child); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
$child = $resultarray[0]['id']; | |
if (!empty($child)){ | |
//make sure the association doesn't exist already or deal with it | |
$current_container = "SELECT parent_entity_id from EntityLink WHERE child_entity_id = $child"; | |
unset($result); | |
$result = usePreparedSelectBlade ($current_container); | |
$resultarray = $result->fetchAll (PDO::FETCH_ASSOC); | |
$current_parent = $resultarray[0]['parent_entity_id']; | |
if ( ($current_parent != $newmachine ) && !empty($current_parent)){ | |
commitUpdateEntityLink('object',$current_parent,'object',$child,'object',$newmachine,'object',$child); | |
} else if (empty($current_parent)) { | |
commitLinkEntities('object', $newmachine,'object',$child); | |
} | |
} else { | |
echo "WARNING: The $vms VM has not been added, but live on this Parent \n"; | |
} | |
} | |
//Auto Tagging | |
function addTagToObject ($facter, $newmachine) { | |
$tags = array($facter['machinetype'], $facter['environment']); | |
$count_tags = count($tags); | |
for ($i = 0; $i < $count_tags; $i++) { | |
rebuildTagChainForEntity ('object', $newmachine, array (getTagByName($tags[$i]))); | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment