123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- <?php
- //-
- // Copyright (c) 2011-2016 Joe Clarke <jclarke@cisco.com>
- // All rights reserved.
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- // 1. Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // 2. Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the distribution.
- // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- // SUCH DAMAGE.
- include_once '../db.inc.php';
- include_once 'swreg.inc.php';
- include_once '../swreg_creds.inc.php';
- require_once '../functions.php';
- require_once 'Log.php';
- function process_macro($name, $value, $hn, $sn, $pid, &$logger)
- {
- $contents = '';
- if (preg_match('/^file:(.*)/', $value, $match)) {
- if (!is_file($match[1])) {
- $logger->crit("Macro {$name} failed to evaluate: file {$match[1]} does not exist");
- exit(1);
- }
- @$contents = file_get_contents(trim($match[1]));
- } elseif (preg_match('/^script:(.*)/', $value, $match)) {
- $script = trim($match[1]);
- $output = array();
- $rc = 0;
- $hn = escapeshellarg($hn);
- $sn = escapeshellarg($sn);
- $pid = escapeshellarg($pid);
- @exec("$script $name $hn $sn $pid", $output, $rc);
- $contents = implode("\n", $output);
- if ($rc != 0) {
- $logger->crit("Macro {$name} failed to evaluate: {$contents}");
- exit(1);
- }
- } else {
- $contents = $value;
- }
- return trim($contents);
- }
- $dsn = "$db_driver:host=$db_host;dbname=$db_name";
- $options = [
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
- PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
- PDO::ATTR_EMULATE_PREPARES => false,
- ];
- try {
- $dbh = new PDO($dsn, $db_user, $db_pass, $options);
- } catch (PDOException $e) {
- die($e->getMessage());
- }
- $logger = Log::singleton('file', LOGFILE, TOOL_NAME . ' : Switch Registrar');
- if ($logger === false) {
- die("Failed to open logfile.\n");
- }
- $mask = Log::MAX(LOG_LEVEL);
- $logger->setMask($mask);
- $pid = $_GET['pid'];
- $sn = $_GET['sn'];
- $version = $_GET['version'];
- $num_ports = $_GET['num_ports'];
- $imagef = $_GET['imagef'];
- header('Content-type: text/plain');
- if (!isset($pid) || !isset($sn) || !isset($version) || !isset($num_ports)) {
- echo "ERROR: Invalid request!\r\n";
- $logger->emerg('Invalid request from ' . $_SERVER['REMOTE_ADDR'] . " pid = '$pid', sn = '$sn', version = '$version', num_ports = '$num_ports'");
- exit(1);
- }
- $logger->debug("Received request from $sn: pid = $pid, version = $version, num_ports = $num_ports");
- $image = null;
- $config = null;
- $found_pid = null;
- $not_configed = "ERROR: Tool not properly configured.\r\n";
- if (isset($PID_ALIASES[$pid])) {
- $pid = $PID_ALIASES[$pid];
- }
- foreach ($ZTP_PIDS as $zpid) {
- if (preg_match("/^$zpid$/", $pid)) {
- if (!isset($IMG_VERS[$zpid])) {
- echo $not_configed;
- $logger->emerg("\$IMG_VERS[$zpid] is not defined in swreg.inc.php!");
- exit(1);
- }
- if (!isset($IMG_FILES[$zpid])) {
- echo $not_configed;
- $logger->emerg("\$IMG_FILES[$zpid] is not defined in swreg.inc.php!");
- exit(1);
- }
- if ($version != $IMG_VERS[$zpid] || $imagef != $IMG_FILES[$zpid]) {
- $image = $IMG_FILES[$zpid];
- }
- if (!isset($START_PORTS[$zpid])) {
- echo $not_configed;
- $logger->emerg("\$START_PORTS[$zpid] is not defined in swreg.inc.php!");
- exit(1);
- }
- $start_port = $START_PORTS[$zpid];
- if (!isset($PORT_TYPES[$zpid])) {
- echo $not_configed;
- $logger->emerg("\$PORT_TYPES[$zpid] is not defined in swreg.inc.php!");
- exit(1);
- }
- $port_type = $PORT_TYPES[$zpid];
- $found_pid = $zpid;
- }
- }
- if ($found_pid === null) {
- call_hook('REQUEST:ERROR', array($_SERVER['REMOTE_ADDR'], $sn, $pid, "Request from unknown PID: {$pid}"));
- $logger->crit("Request from unknown PID: $pid");
- echo "ERROR: Unknown PID: $pid\r\n";
- exit(1);
- }
- $use_pnp = false;
- if (USE_PNP === true) {
- foreach ($PNP_PATTERNS as $pattern => $ipnp) {
- if (preg_match("/$pattern/", $image)) {
- $use_pnp = $ipnp;
- break;
- }
- }
- }
- $sql = 'SELECT assigned_switch, max_ports, checked_out FROM DEVICE_MAP WHERE serial_number = ?';
- $res = null;
- $sth = null;
- try {
- $sth = $dbh->prepare($sql);
- $res = $sth->execute(array($sn));
- } catch (PDOException $e) {
- echo 'ERROR: Failed to get switch list: ' . $e->getMessage() . "\r\n";
- call_hook('REQUEST:ERROR', array($_SERVER['REMOTE_ADDR'], $sn, $pid, 'Failed to get switch list: ' . $e->getMessage()));
- $logger->crit('Failed to get switch list: ' . $e->getMessage());
- exit(1);
- }
- $row = $sth->fetch();
- $sth->closeCursor();
- $max_ports = $row['max_ports'];
- if ($row['checked_out'] == 0) {
- echo "ERROR: Switch has not yet been provisioned via the web\r\n";
- $logger->crit("Switch $sn ({$_SERVER['REMOTE_ADDR']}) has not yet been provisioned via the web");
- call_hook('REQUEST:UNKNOWN', array($_SERVER['REMOTE_ADDR'], $sn, $pid));
- exit(1);
- }
- if ($max_ports > $num_ports) {
- echo "ERROR: Switch has been provisioned for $max_ports but this physical switch only has $num_ports\r\n";
- call_hook('REQUEST:ERROR', array($_SERVER['REMOTE_ADDR'], $sn, $pid, "Switch has been provisioned for {$max_ports} but this physical switch only has {$num_ports}"));
- $logger->crit("Switch $sn has been provisioned for $max_ports but this physical switch only has $num_ports");
- exit(1);
- }
- $sql = 'SELECT s.name AS hostname, s.location AS snmp_loc, s.is_idf AS is_idf, a.address AS ip, a.router AS gw, a.mask AS mask, a.mgmt_vlan AS mgmt_vlan, a.location AS location FROM SWITCHES s, ADDRESSES a WHERE s.name = ? AND s.ip_address = a.address';
- try {
- $sth = $dbh->prepare($sql);
- $res = $sth->execute(array($row['assigned_switch']));
- } catch (PDOException $e) {
- echo 'ERROR: Failed to get logical switch details: ' . $e->getMessage() . "\r\n";
- call_hook('REQUEST:ERROR', array($_SERVER['REMOTE_ADDR'], $sn, $pid, 'Failed to get logical switch details: ' . $e->getMessage()));
- $logger->crit('Failed to get logical switch details: ' . $e->getMessage());
- exit(1);
- }
- $row = $sth->fetch();
- $sth->closeCursor();
- call_hook('REQUEST:NEW', array($_SERVER['REMOTE_ADDR'], $row['hostname'], $sn, $pid, $version, $num_ports, $imagef));
- if ($image !== null && !file_exists(TFTPBOOT . '/' . $image)) {
- echo "ERROR: Image file {$image} does not exist in " . TFTPBOOT . "\r\n";
- call_hook('REQUEST:ERROR', array($_SERVER['REMOTE_ADDR'], $sn, $pid, "Image file {$image} does not exist in " . TFTPBOOT));
- $logger->crit("Image file {$image} for {$sn}, {$pid} does not exist in " . TFTPBOOT);
- exit(1);
- }
- $sql = 'UPDATE DEVICE_MAP SET provisioned_status = ? WHERE serial_number = ?';
- try {
- $sth = $dbh->prepare($sql);
- $sth->execute(array(PROVISION_IN_PROGRESS, $sn));
- $sth->closeCursor();
- } catch (PDOException $e) {
- call_hook('REQUEST:ERROR', array($_SERVER['REMOTE_ADDR'], $sn, $pid, "Failed to update switch provisioned status: {$e->getMessage()}"));
- echo "ERROR: Failed to update switch provisioned status: {$e->getMessage()}\r\n";
- $logger->crit("Failed to update switch provisioned status: {$e->getMessage()}");
- exit(1);
- }
- $port_contents = "interface range {$port_type}{$start_port} - $max_ports\n";
- if (file_exists(PORT_TMPL_DIR . '/devices/' . $row['hostname'] . '-ports.tmpl')) {
- $port_contents = file_get_contents(PORT_TMPL_DIR . '/devices/' . $row['hostname'] . '-ports.tmpl');
- if (file_exists(PORT_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-ports.tmpl')) {
- $port_contents .= file_get_contents(PORT_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-ports.tmpl');
- }
- } else {
- if (file_exists(PORT_TMPL_DIR . '/ports.tmpl')) {
- $port_contents .= file_get_contents(PORT_TMPL_DIR . '/ports.tmpl');
- }
- if (file_exists(PORT_TMPL_DIR . '/' . $found_pid . '/ports.tmpl')) {
- $port_contents .= file_get_contents(PORT_TMPL_DIR . '/' . $found_pid . '/ports.tmpl');
- }
- if (file_exists(PORT_TMPL_DIR . '/DYNAMIC/ports.tmpl')) {
- $port_contents .= file_get_contents(PORT_TMPL_DIR . '/DYNAMIC/ports.tmpl');
- }
- if (file_exists(PORT_TMPL_DIR . '/DYNAMIC/' . $found_pid . '/ports.tmpl')) {
- $port_contents .= file_get_contents(PORT_TMPL_DIR . '/DYNAMIC/' . $found_pid . '/ports.tmpl');
- }
- if (file_exists(PORT_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-ports.tmpl')) {
- $port_contents .= file_get_contents(PORT_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-ports.tmpl');
- }
- }
- $snmp_loc = $row['snmp_loc'];
- if (!$snmp_loc || $snmp_loc == '') {
- $snmp_loc = $row['location'];
- }
- $ew_keywords = preg_replace("/\s/", '_', $snmp_loc);
- $ew_role = 'ACCESS-SWITCH';
- if ($row['is_idf'] == 1) {
- $ew_role = 'IDF-SWITCH';
- }
- $contents = '';
- if (file_exists(DEVICE_TMPL_DIR . '/device.tmpl')) {
- $contents .= file_get_contents(DEVICE_TMPL_DIR . '/device.tmpl');
- }
- if (file_exists(DEVICE_TMPL_DIR . '/' . $found_pid . '/device.tmpl')) {
- $contents .= file_get_contents(DEVICE_TMPL_DIR . '/' . $found_pid . '/device.tmpl');
- }
- if (file_exists(DEVICE_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-device.tmpl')) {
- $contents .= file_get_contents(DEVICE_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-device.tmpl');
- }
- $contents .= "end\n";
- $eem_contents = '';
- if (file_exists(EEM_TMPL_DIR . '/eem.tmpl')) {
- $eem_contents = file_get_contents(EEM_TMPL_DIR . '/eem.tmpl');
- }
- if (file_exists(EEM_TMPL_DIR . '/' . $found_pid . '/eem.tmpl')) {
- $eem_contents .= file_get_contents(EEM_TMPL_DIR . '/' . $found_pid . '/eem.tmpl');
- }
- if (file_exists(EEM_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-eem.tmpl')) {
- $eem_contents .= file_get_contents(EEM_TMPL_DIR . '/device-overrides/' . $row['hostname'] . '-eem.tmpl');
- }
- $contents = str_replace('%%EEM_CONFIG%%', $eem_contents, $contents);
- $vlan_contents = file_get_contents(VLAN_TMPL_DIR . '/' . strtolower($row['location']) . '-vlan.tmpl');
- $contents = str_replace('%%VLAN_TMPL%%', $vlan_contents, $contents);
- $contents = str_replace('%%PORT_CONFIG%%', $port_contents, $contents);
- $contents = str_replace('%%MGMT_VLAN%%', $row['mgmt_vlan'], $contents);
- $contents = str_replace('%%HOSTNAME%%', $row['hostname'], $contents);
- $contents = str_replace('%%EW_DOMAIN%%', $row['location'], $contents);
- $contents = str_replace('%%EW_KEYWORDS%%', $ew_keywords, $contents);
- $contents = str_replace('%%EW_ROLE%%', $ew_role, $contents);
- $contents = str_replace('%%VTP_DOMAIN%%', $row['location'], $contents);
- $contents = str_replace('%%MGMT_IP%%', $row['ip'], $contents);
- $contents = str_replace('%%MGMT_MASK%%', $row['mask'], $contents);
- $contents = str_replace('%%MGMT_GW%%', $row['gw'], $contents);
- $contents = str_replace('%%SNMP_LOCATION%%', $snmp_loc, $contents);
- if (MAP_V6 === true) {
- $octets = explode('.', $row['ip']);
- $contents = str_replace('%%MGMT_IP6%%', IPV6_PREFIX . ':' . $octets[3], $contents);
- $contents = str_replace('%%MGMT_PREFIXLEN%%', IPV6_PREFIXLEN, $contents);
- $contents = str_replace('%%MGMT_GW6%%', IPV6_GW, $contents);
- }
- $contents = str_replace('%%START_PORT%%', $start_port, $contents);
- $contents = str_replace('%%MAX_PORT%%', $max_ports, $contents);
- // XXX: TODO
- $contents = str_replace('%%STACK_CONFIG%%', '!', $contents);
- // Replace creds
- $contents = str_replace('%%ADMIN_SECRET%%', ADMIN_SECRET, $contents);
- $contents = str_replace('%%TACACS_KEY%%', TACACS_KEY, $contents);
- $contents = str_replace('%%EW_SHARED_SECRET%%', EW_SHARED_SECRET, $contents);
- $contents = str_replace('%%EW_MGMT_SHARED_SECRET%%', EW_MGMT_SHARED_SECRET, $contents);
- $contents = str_replace('%%SNMPV3_USER%%', SNMPV3_USER, $contents);
- $contents = str_replace('%%SNMPV3_PASS%%', SNMPV3_PASS, $contents);
- if (isset($VLAN_OVERRIDES) && isset($VLAN_OVERRIDES[$row['location']])) {
- foreach ($VLAN_OVERRIDES[$row['location']] as $vn => $vi) {
- $VLANS[$vn] = $vi;
- }
- }
- foreach ($VLANS as $vn => $vi) {
- $vname = strtoupper($vn);
- $vname = str_replace(' ', '_', $vname);
- $macro = '%%' . $vname . '_VLAN%%';
- $contents = str_replace($macro, $vi, $contents);
- }
- $custom_macros = array();
- if (isset($CUSTOM_MACROS)) {
- foreach ($CUSTOM_MACROS as $macro => $mv) {
- $custom_macros[$macro] = process_macro($macro, $mv, $row['hostname'], $sn, $found_pid, $logger);
- }
- }
- if (isset($MDF_OVERRIDES) && isset($MDF_OVERRIDES[$row['location']])) {
- foreach ($MDF_OVERRIDES[$row['locations']] as $macro => $mv) {
- $custom_macros[$macro] = process_macro($macro, $mv, $row['hostname'], $sn, $found_pid, $logger);
- }
- }
- if (isset($PID_MACROS) && isset($PID_MACROS[$found_pid])) {
- foreach ($PID_MACROS[$found_pid] as $macro => $mv) {
- $custom_macros[$macro] = process_macro($macro, $mv, $row['hostname'], $sn, $found_pid, $logger);
- }
- }
- foreach ($custom_macros as $macro => $mv) {
- $contents = str_replace("%%$macro%%", $mv, $contents);
- }
- umask(0022);
- $fd = @fopen(DEVICE_CONFIG_DIR . '/' . $row['hostname'] . '-config.txt', 'w');
- fwrite($fd, $contents);
- fclose($fd);
- $fd = @fopen(DEVICE_TMP_DIR . '/' . $row['hostname'] . '-config.txt', 'w');
- fclose($fd);
- chmod(DEVICE_TMP_DIR . '/' . $row['hostname'] . '-config.txt', 0666);
- if ($use_pnp) {
- $error = '';
- $ticket = apicGetTicket(APIC_HOST, APIC_USER, APIC_PASS, $error);
- if ($ticket === false) {
- $logger->error("Failed to get ticket from APIC-EM: $error");
- $use_pnp = false;
- } else {
- $proj = apicGetProject(APIC_HOST, $ticket, APIC_PROJECT, $error);
- if ($proj === false) {
- $logger->error("Failed to get project from APIC-EM: $error");
- $use_pnp = false;
- } else {
- $ares = apicAddDevice(APIC_HOST, $ticket, $proj['id'], $row['hostname'], $sn, $pid, $error, $config, $image);
- if ($ares === false) {
- $logger->error("Failed to add device to APIC-EM: $error");
- $use_pnp = false;
- }
- }
- }
- }
- if ($use_pnp) {
- echo "PNP\r\n";
- $logger->info("Successfully provisioned switch $sn ($pid) {$row['hostname']} as a PnP device");
- } else {
- echo "Config: {$row['hostname']}-config.txt\r\n";
- if (isset($SDM_PROFILES[$pid])) {
- echo "SDM: {$SDM_PROFILES[$pid]}\r\n";
- }
- if ($image !== null) {
- echo "Image: $image\r\n";
- }
- $logger->info("Successfully provisioned switch $sn ($pid) {$row['hostname']}");
- }
- $logger->close();
|