/** * Constructor which load an existent lab or create an empty one. * * @param string $f the file of the lab with full path * @param int $tenant Tenant ID * @return void */ public function __construct($f, $tenant) { $modified = False; if (!is_file($f)) { // File does not exist, create a new empty lab $this->filename = basename($f); $this->path = dirname($f); $this->tenant = (int) $tenant; if (!checkLabFilename($this->filename)) { // Invalid filename error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]); throw new Exception('20001'); } if (!checkLabPath($this->path)) { // Invalid path error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]); throw new Exception('20002'); } $this->name = substr(basename($f), 0, -4); $this->id = genUuid(); $modified = True; } else { // Load the existent lab $this->filename = basename($f); $this->path = dirname($f); $this->tenant = (int) $tenant; if (!checkLabFilename($this->filename)) { // Invalid filename error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]); throw new Exception('20001'); } if (!checkLabPath($this->path)) { // Invalid path error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]); throw new Exception('20002'); } libxml_use_internal_errors(true); $xml = simplexml_load_file($f); if (!$xml) { // Invalid XML document error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20003]); throw new Exception('20003'); } // Lab name $result = $xml->xpath('//lab/@name'); if (empty($result)) { // Invalid UNetLab file (attribute is missing) error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20004]); throw new Exception('20004'); return; } else { if (!checkLabName($result[0])) { // Attribute not valid error_log('ERROR: ' . $f . ' ' . $GLOBALS['messages'][20005]); throw new Exception('20005'); return; } else { $this->name = (string) $result[0]; } } // Lab ID $result = $xml->xpath('//lab/@id'); if (empty($result)) { // Lab ID not set, create a new one $this->id = genUuid(); error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20011]); $modified = True; } else { if (!checkUuid($result[0])) { // Attribute not valid $this->id = genUuid(); error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20012]); $modified = True; } else { $this->id = (string) $result[0]; } } // Lab description $result = (string) array_pop($xml->xpath('//lab/description')); if (strlen($result) !== 0) { $this->description = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE); } else { if (strlen($result) !== 0) { error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20006]); } } // Lab author $result = (string) array_pop($xml->xpath('//lab/@author')); if (strlen($result) !== 0) { $this->author = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE); } else { if (strlen($result) !== 0) { error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20007]); } } // Lab version $result = (string) array_pop($xml->xpath('//lab/@version')); if (strlen($result) !== 0 && (int) $result >= 0) { $this->version = $result; } else { if (strlen($result) !== 0) { error_log('WARNING: ' . $f . ' ' . $GLOBALS['messages'][20008]); } } // Lab networks foreach ($xml->xpath('//lab/topology/networks/network') as $network) { $w = array(); if (isset($network->attributes()->id)) { $w['id'] = (string) $network->attributes()->id; } if (isset($network->attributes()->left)) { $w['left'] = (string) $network->attributes()->left; } if (isset($network->attributes()->name)) { $w['name'] = (string) $network->attributes()->name; } if (isset($network->attributes()->top)) { $w['top'] = (string) $network->attributes()->top; } if (isset($network->attributes()->type)) { $w['type'] = (string) $network->attributes()->type; } try { $this->networks[$w['id']] = new Network($w, $w['id'], $this->tenant); } catch (Exception $e) { // Invalid network error_log('WARNING: ' . $f . ':net' . $w['id'] . ' ' . $GLOBALS['messages'][20009]); error_log((string) $e); continue; } } // Lab nodes (networks must be alredy loaded) foreach ($xml->xpath('//lab/topology/nodes/node') as $node_id => $node) { $n = array(); if (isset($node->attributes()->config)) { $n['config'] = (string) $node->attributes()->config; } if (isset($node->attributes()->console)) { $n['console'] = (string) $node->attributes()->console; } if (isset($node->attributes()->cpu)) { $n['cpu'] = (int) $node->attributes()->cpu; } if (isset($node->attributes()->delay)) { $n['delay'] = (string) $node->attributes()->delay; } if (isset($node->attributes()->ethernet)) { $n['ethernet'] = (int) $node->attributes()->ethernet; } if (isset($node->attributes()->icon)) { $n['icon'] = (string) $node->attributes()->icon; } if (isset($node->attributes()->id)) { $n['id'] = (int) $node->attributes()->id; } if (isset($node->attributes()->idlepc)) { $n['idlepc'] = (string) $node->attributes()->idlepc; } if (isset($node->attributes()->image)) { $n['image'] = (string) $node->attributes()->image; } if (isset($node->attributes()->left)) { $n['left'] = (string) $node->attributes()->left; } if (isset($node->attributes()->name)) { $n['name'] = (string) $node->attributes()->name; } if (isset($node->attributes()->nvram)) { $n['nvram'] = (int) $node->attributes()->nvram; } if (isset($node->attributes()->ram)) { $n['ram'] = (int) $node->attributes()->ram; } if (isset($node->attributes()->serial)) { $n['serial'] = (int) $node->attributes()->serial; } if (isset($node->attributes()->template)) { $n['template'] = (string) $node->attributes()->template; } if (isset($node->attributes()->top)) { $n['top'] = (string) $node->attributes()->top; } if (isset($node->attributes()->type)) { $n['type'] = (string) $node->attributes()->type; } if (isset($node->attributes()->uuid)) { $n['uuid'] = (string) $node->attributes()->uuid; } try { $this->nodes[$n['id']] = new Node($n, $n['id'], $this->tenant, $this->id); } catch (Exception $e) { // Invalid node error_log('WARNING: ' . $f . ':node' . $n['id'] . ' ' . $GLOBALS['messages'][20010]); error_log((string) $e); continue; } // Slot must be loaded before interfaces foreach ($node->slot as $slot) { // Loading configured slots for this node $s = array(); if (isset($slot->attributes()->id)) { $s['id'] = (string) $slot->attributes()->id; } if (isset($slot->attributes()->module)) { $s['module'] = (string) $slot->attributes()->module; } if ($this->nodes[$n['id']]->setSlot($s['id'], $s['module']) !== 0) { error_log('WARNING: ' . $f . ':node' . $n['id'] . ':slot' . $s['id'] . ' ' . $GLOBALS['messages'][20013]); } } foreach ($node->interface as $interface) { // Loading configured interfaces for this node $i = array(); if (isset($interface->attributes()->id)) { $i['id'] = (string) $interface->attributes()->id; } if (isset($interface->attributes()->network_id)) { $i['network_id'] = (string) $interface->attributes()->network_id; } if (isset($interface->attributes()->remote_id)) { $i['remote_id'] = (string) $interface->attributes()->remote_id; } if (isset($interface->attributes()->remote_if)) { $i['remote_if'] = (string) $interface->attributes()->remote_if; } if (isset($interface->attributes()->remote_host)) { $i['remote_host'] = (string) $interface->attributes()->remote_host; } if (isset($interface->attributes()->type)) { $i['type'] = (string) $interface->attributes()->type; } switch ($i['type']) { default: error_log('WARNING: ' . $f . ':node' . $n['id'] . ':inv' . $s['id'] . ' ' . $GLOBALS['messages'][20016]); break; case 'ethernet': if ($this->nodes[$n['id']]->linkInterface($i) !== 0) { error_log('WARNING: ' . $f . ':node' . $n['id'] . ':eth' . $i['id'] . ' ' . $GLOBALS['messages'][20014]); } break; case 'serial': // Serial if ($this->nodes[$n['id']]->linkInterface($i) !== 0) { error_log('WARNING: ' . $f . ':node' . $n['id'] . ':ser' . $i['id'] . ' ' . $GLOBALS['messages'][20015]); } break; } } } // startup-config foreach ($xml->xpath('//lab/objects/configs/config') as $config) { $node_id = 0; $config_data = ''; if (isset($config->attributes()->id)) { $node_id = (string) $config->attributes()->id; } $result = (string) array_pop($config->xpath('.')); if (strlen($result) > 0) { $config_data = base64_decode($result); } $rc = $this->nodes[$node_id]->setConfigData($config_data); if ($rc != 0) { error_log('WARNING: ' . $f . ':cfg' . $node_id . ' ' . $GLOBALS['messages'][20037]); continue; } } // Lab Pictures foreach ($xml->xpath('//lab/objects/pictures/picture') as $picture) { $p = array(); if (isset($picture->attributes()->id)) { $p['id'] = (string) $picture->attributes()->id; } if (isset($picture->attributes()->name)) { $p['name'] = (string) $picture->attributes()->name; } if (isset($picture->attributes()->type)) { $p['type'] = (string) $picture->attributes()->type; } $result = (string) array_pop($picture->xpath('./data')); if (strlen($result) > 0) { $p['data'] = base64_decode($result); } $result = (string) array_pop($picture->xpath('./map')); if (strlen($result) > 0) { $p['map'] = html_entity_decode($result); } try { $this->pictures[$p['id']] = new Picture($p, $p['id']); } catch (Exception $e) { // Invalid picture error_log('WARNING: ' . $f . ':pic' . $p['id'] . ' ' . $GLOBALS['messages'][20020]); error_log((string) $e); continue; } } // Update attached network count $this->setNetworkCount(); } if ($modified) { // Need to save $rc = $this->save(); if ($rc != 0) { throw new Exception($rc); return $rc; } } return 0; }
/** * Constructor which load an existent lab or create an empty one. * * @param string $f the file of the lab with full path * @param int $tenant Tenant ID * @return void */ public function __construct($f, $tenant) { $modified = False; if (!is_file($f)) { // File does not exist, create a new empty lab $this->filename = basename($f); $this->path = dirname($f); $this->tenant = (int) $tenant; if (!checkLabFilename($this->filename)) { // Invalid filename error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]); throw new Exception('20001'); } if (!checkLabPath($this->path)) { // Invalid path error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]); throw new Exception('20002'); } $this->name = substr(basename($f), 0, -4); $this->id = genUuid(); $modified = True; $this->scripttimeout = 600; } else { // Load the existent lab $this->filename = basename($f); $this->path = dirname($f); $this->tenant = (int) $tenant; if (!checkLabFilename($this->filename)) { // Invalid filename error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20001]); throw new Exception('20001'); } if (!checkLabPath($this->path)) { // Invalid path error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20002]); throw new Exception('20002'); } libxml_use_internal_errors(true); $xml = simplexml_load_file($f); if (!$xml) { // Invalid XML document error_log(date('M d H:i:s ') . 'ERROR: ' . $f . ' ' . $GLOBALS['messages'][20003]); throw new Exception('20003'); } // Lab name $patterns[0] = '/\\.unl$/'; $replacements[0] = ''; $this->name = preg_replace($patterns, $replacements, basename($f)); // Lab ID $result = $xml->xpath('//lab/@id'); if (empty($result)) { // Lab ID not set, create a new one $this->id = genUuid(); error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20011]); $modified = True; } else { if (!checkUuid($result[0])) { // Attribute not valid $this->id = genUuid(); error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20012]); $modified = True; } else { $this->id = (string) $result[0]; } } // Lab description $result = (string) array_pop($xml->xpath('//lab/description')); if (strlen($result) !== 0) { $this->description = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE); } else { if (strlen($result) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20006]); } } // Lab body $result = (string) array_pop($xml->xpath('//lab/body')); if (strlen($result) !== 0) { $this->body = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE); } else { if (strlen($result) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20006]); } } // Lab author $result = (string) array_pop($xml->xpath('//lab/@author')); if (strlen($result) !== 0) { $this->author = htmlspecialchars($result, ENT_DISALLOWED, 'UTF-8', TRUE); } else { if (strlen($result) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20007]); } } // Lab version $result = (string) array_pop($xml->xpath('//lab/@version')); if (strlen($result) !== 0 && (int) $result >= 0) { $this->version = $result; } else { if (strlen($result) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20008]); } } // Lab networks foreach ($xml->xpath('//lab/topology/networks/network') as $network) { $w = array(); if (isset($network->attributes()->id)) { $w['id'] = (string) $network->attributes()->id; } if (isset($network->attributes()->left)) { $w['left'] = (string) $network->attributes()->left; } if (isset($network->attributes()->name)) { $w['name'] = (string) $network->attributes()->name; } if (isset($network->attributes()->top)) { $w['top'] = (string) $network->attributes()->top; } if (isset($network->attributes()->type)) { $w['type'] = (string) $network->attributes()->type; } try { $this->networks[$w['id']] = new Network($w, $w['id'], $this->tenant); } catch (Exception $e) { // Invalid network error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':net' . $w['id'] . ' ' . $GLOBALS['messages'][20009]); error_log(date('M d H:i:s ') . (string) $e); continue; } } // Lab nodes (networks must be alredy loaded) foreach ($xml->xpath('//lab/topology/nodes/node') as $node_id => $node) { $n = array(); if (isset($node->attributes()->config)) { $n['config'] = (string) $node->attributes()->config; } if (isset($node->attributes()->console)) { $n['console'] = (string) $node->attributes()->console; } if (isset($node->attributes()->cpu)) { $n['cpu'] = (int) $node->attributes()->cpu; } if (isset($node->attributes()->delay)) { $n['delay'] = (string) $node->attributes()->delay; } if (isset($node->attributes()->ethernet)) { $n['ethernet'] = (int) $node->attributes()->ethernet; } if (isset($node->attributes()->icon)) { $n['icon'] = (string) $node->attributes()->icon; } if (isset($node->attributes()->id)) { $n['id'] = (int) $node->attributes()->id; } if (isset($node->attributes()->idlepc)) { $n['idlepc'] = (string) $node->attributes()->idlepc; } if (isset($node->attributes()->image)) { $n['image'] = (string) $node->attributes()->image; } if (isset($node->attributes()->left)) { $n['left'] = (string) $node->attributes()->left; } if (isset($node->attributes()->name)) { $n['name'] = (string) $node->attributes()->name; } if (isset($node->attributes()->nvram)) { $n['nvram'] = (int) $node->attributes()->nvram; } if (isset($node->attributes()->ram)) { $n['ram'] = (int) $node->attributes()->ram; } if (isset($node->attributes()->serial)) { $n['serial'] = (int) $node->attributes()->serial; } if (isset($node->attributes()->template)) { $n['template'] = (string) $node->attributes()->template; } if (isset($node->attributes()->top)) { $n['top'] = (string) $node->attributes()->top; } if (isset($node->attributes()->type)) { $n['type'] = (string) $node->attributes()->type; } if (isset($node->attributes()->uuid)) { $n['uuid'] = (string) $node->attributes()->uuid; } $n['config'] == 'Exported' ? $n['config'] = '1' : $n['config']; // Fix startup-config $n['config'] == 'None' ? $n['config'] = '0' : $n['config']; // Fix startup-config // If config is empty, force "None" $result = (string) array_pop($xml->xpath('//lab/objects/configs/config[@id="' . $n['id'] . '"]')); if (strlen($result) == 0) { $n['config'] = 0; $config_data = False; } else { $config_data = base64_decode($result); } // F5 needs a first mac address if ($n['template'] == "bigip") { if (isset($node->attributes()->firstmac)) { $n['firstmac'] = (string) $node->attributes()->firstmac; } else { $n['firstmac'] = (string) '00:' . sprintf('%02x', $this->tenant) . ':' . sprintf('%02x', $this->id / 512) . ':' . sprintf('%02x', $this->id % 512) . ':00:10'; } } try { $this->nodes[$n['id']] = new Node($n, $n['id'], $this->tenant, $this->id); } catch (Exception $e) { // Invalid node error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ' ' . $GLOBALS['messages'][20010]); error_log(date('M d H:i:s ') . (string) $e); continue; } // Slot must be loaded before interfaces foreach ($node->slot as $slot) { // Loading configured slots for this node $s = array(); if (isset($slot->attributes()->id)) { $s['id'] = (string) $slot->attributes()->id; } if (isset($slot->attributes()->module)) { $s['module'] = (string) $slot->attributes()->module; } if ($this->nodes[$n['id']]->setSlot($s['id'], $s['module']) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':slot' . $s['id'] . ' ' . $GLOBALS['messages'][20013]); } } foreach ($node->interface as $interface) { // Loading configured interfaces for this node $i = array(); if (isset($interface->attributes()->id)) { $i['id'] = (string) $interface->attributes()->id; } if (isset($interface->attributes()->network_id)) { $i['network_id'] = (string) $interface->attributes()->network_id; } if (isset($interface->attributes()->remote_id)) { $i['remote_id'] = (string) $interface->attributes()->remote_id; } if (isset($interface->attributes()->remote_if)) { $i['remote_if'] = (string) $interface->attributes()->remote_if; } if (isset($interface->attributes()->remote_host)) { $i['remote_host'] = (string) $interface->attributes()->remote_host; } if (isset($interface->attributes()->type)) { $i['type'] = (string) $interface->attributes()->type; } switch ($i['type']) { default: error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':inv' . $s['id'] . ' ' . $GLOBALS['messages'][20016]); break; case 'ethernet': if ($this->nodes[$n['id']]->linkInterface($i) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':eth' . $i['id'] . ' ' . $GLOBALS['messages'][20014]); } break; case 'serial': // Serial if ($this->nodes[$n['id']]->linkInterface($i) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':node' . $n['id'] . ':ser' . $i['id'] . ' ' . $GLOBALS['messages'][20015]); } break; } } // startup-config (read before) if ($config_data !== False) { $rc = $this->nodes[$n['id']]->setConfigData($config_data); if ($rc != 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':cfg' . $node_id . ' ' . $GLOBALS['messages'][20037]); } } } // lab script timeout $result = (string) array_pop($xml->xpath('//lab/@scripttimeout')); if (strlen($result) !== 0 && (int) $result >= 300) { $this->scripttimeout = $result; } else { if (strlen($result) !== 0) { error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ' ' . $GLOBALS['messages'][20045]); $this->scripttimeout = 300; } } // Lab Pictures foreach ($xml->xpath('//lab/objects/pictures/picture') as $picture) { $p = array(); if (isset($picture->attributes()->id)) { $p['id'] = (string) $picture->attributes()->id; } if (isset($picture->attributes()->name)) { $p['name'] = (string) $picture->attributes()->name; } if (isset($picture->attributes()->type)) { $p['type'] = (string) $picture->attributes()->type; } $result = (string) array_pop($picture->xpath('./data')); if (strlen($result) > 0) { $p['data'] = base64_decode($result); } $result = (string) array_pop($picture->xpath('./map')); if (strlen($result) > 0) { $p['map'] = html_entity_decode($result); } try { $this->pictures[$p['id']] = new Picture($p, $p['id']); } catch (Exception $e) { // Invalid picture error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':pic' . $p['id'] . ' ' . $GLOBALS['messages'][20020]); error_log(date('M d H:i:s ') . (string) $e); continue; } } // Text Objects foreach ($xml->xpath('//lab/objects/textobjects/textobject') as $textobject) { $p = array(); if (isset($textobject->attributes()->id)) { $p['id'] = (string) $textobject->attributes()->id; } if (isset($textobject->attributes()->name)) { $p['name'] = (string) $textobject->attributes()->name; } if (isset($textobject->attributes()->type)) { $p['type'] = (string) $textobject->attributes()->type; } $result = (string) array_pop($textobject->xpath('./data')); if (strlen($result) > 0) { $p['data'] = $result; } try { $this->textobjects[$p['id']] = new TextObject($p, $p['id']); } catch (Exception $e) { // Invalid picture error_log(date('M d H:i:s ') . 'WARNING: ' . $f . ':obj' . $p['id'] . ' ' . $GLOBALS['messages'][20041]); error_log(date('M d H:i:s ') . (string) $e); continue; } } // Update attached network count $this->setNetworkCount(); } if ($modified) { // Need to save $rc = $this->save(); if ($rc != 0) { throw new Exception($rc); return $rc; } } return 0; }