952 days continuous production uptime, 40k+ tp/s single node. Original corpo Bitbucket history not included — clean archive commit.
1559 lines
72 KiB
PHP
1559 lines
72 KiB
PHP
<?php
|
|
/**
|
|
* ResourceManager Class
|
|
*
|
|
* This singleton class is responsible for establishing, and maintaining, connections to external services.
|
|
*
|
|
* As of this writing, the following services are supported:
|
|
*
|
|
* - DynamoDB (Ddb)
|
|
* - Cache (memcached or redis)
|
|
* - RabbitMQ (SSL and Non-SSL)
|
|
* - Logger service (a secondary, off-zone nosql repo for storing log info)
|
|
* - Admin (RabbitMQ) - connection resource to the GA Admin Server
|
|
*
|
|
* When something in the framework needs to access a service, then they statically call the fetchResource() method
|
|
* in this class to obtain the resource object to the desired service.
|
|
*
|
|
* Successful requests will return a resource object, otherwise a null value is returned.
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-07-17 mks initial coding begins
|
|
* 06-29-17 mks CORE-458: mysql resource management added
|
|
* 09-12-17 mks CORE-561: rip out mysql stuffs and replace with PDO stuffs
|
|
* 03-02-18 mks CORE-680: deprecated trace logging
|
|
* 05-04-18 mks _INF-188: wh code
|
|
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
|
* 07-10-18 mks CORE-773: replaced echo statements with consoleLog()
|
|
* 07-23-18 mks CORE-1097: refactoring for mongo admin resources (master, slave)
|
|
* 07-24-18 mks CORE-1099: deprecated mongo slave resource allocation and management
|
|
* 08-02-18 mks CORE-774: PHP7.2 exception handling
|
|
* 08-21-18 mks DB-49: fixed code where ReadPreference was being replaced with intval causing exception
|
|
* 08-22-18 mks DB-49: making console log the default output vector, positive milestone checks added
|
|
* 01-08-20 mks DB-150: PHP7.4 class member type-casting
|
|
* 04-05-20 mks ECI-136: commented-out some unused member variables
|
|
* 07-29-30 mks DB-156: tercero integration and support (mongodb)
|
|
*
|
|
*/
|
|
|
|
use Aws\DynamoDb\DynamoDbClient as DynamoDbClientAlias;
|
|
use MongoDB\Driver\Manager as ManagerAlias;
|
|
use PhpAmqpLib\Connection\AMQPStreamConnection;
|
|
use PhpAmqpLib\Connection\AMQPSSLConnection;
|
|
|
|
class gasResourceManager {
|
|
private string $class;
|
|
private static ?string $location = null; // used in fetchResource() to determine which resource to init
|
|
private static ?gasResourceManager $instance = null;
|
|
private static string $certPath;
|
|
private static bool $debug = false;
|
|
private static string $certFile;
|
|
private static string $caFile;
|
|
private static bool $resourcesChecked = false;
|
|
private static string $myID = 'RESM: '; // resource manager tag for console error output
|
|
|
|
// IF YOU ADD NEW BROKER SERVICES, UPDATE THIS ARRAY!!!
|
|
private static array $brokerServices = [ CONFIG_BROKER_APPSERVER, BROKER_SEGUNDO, BROKER_TERCERO, BROKER_ADMIN ];
|
|
|
|
private static gacErrorLogger $logger;
|
|
|
|
public static ?array $cfgDdb;
|
|
public static ?array $cfgBroker;
|
|
public static ?array $cfgSegundo;
|
|
public static ?array $cfgTercero;
|
|
public static ?array $cfgAdmin;
|
|
public static ?array $cfgLogger;
|
|
public static ?array $cfgSecurity;
|
|
public static ?array $cfgCache;
|
|
public static ?array $cfgPDO;
|
|
public static ?array $cfgMongo;
|
|
public static bool $IPL = true;
|
|
public static bool $available = false;
|
|
public static bool $cacheAvailable = false;
|
|
public static bool $ddbAvailable = false;
|
|
// public static bool $rabbitAvailable = false;
|
|
public static bool $brokerAvailable = false;
|
|
public static bool $adminAvailable = false;
|
|
public static bool $segundoAvailable = false;
|
|
public static bool $terceroAvailable = false;
|
|
public static bool $PDOAvailable = false;
|
|
public static bool $PDOEnabled = false;
|
|
public static bool $PDOSlaveAvailable = false;
|
|
public static bool $PDOSlaveEnabled = false;
|
|
public static bool $mongoEnabled = false;
|
|
public static bool $mongoMasterAvailable = false;
|
|
// public static bool $mongoSlaveAvailable = false;
|
|
public static bool $mongoWHMasterAvailable = false;
|
|
// public static bool $mongoWHSlaveAvailable = false;
|
|
public static bool $mongoSegundoMasterAvailable = false;
|
|
public static bool $PDOWHMasterAvailable = false;
|
|
public static bool $PDOWHSlaveAvailable = false;
|
|
public static bool $mongoAdminMasterAvailable = false;
|
|
public static bool $mongoTerceroMasterAvailable = false;
|
|
// public static bool $mongoAdminSlaveAvailable = false;
|
|
|
|
private static ?DynamoDbClientAlias $resDdb = null;
|
|
private static ?gasCache $resCache = null;
|
|
private static ?AMQPStreamConnection $resBroker = null;
|
|
private static ?AMQPStreamConnection $resSegundo = null;
|
|
private static ?AMQPStreamConnection $resTercero = null;
|
|
private static ?AMQPStreamConnection $resAdmin = null;
|
|
private static ?PDO $resPDO = null;
|
|
private static ?PDO $resPDOSlave = null;
|
|
private static ?PDO $resPDOWHMaster = null;
|
|
private static ?PDO $resPDOWHSlave = null;
|
|
private static ?ManagerAlias $resMongoMaster = null;
|
|
private static ?ManagerAlias $resMongoWHMaster = null;
|
|
private static ?ManagerAlias $resMongoSegundoMaster = null;
|
|
private static ?ManagerAlias $resMongoAdminMaster = null;
|
|
private static ?ManagerAlias $resMongoTerceroMaster = null;
|
|
|
|
|
|
/**
|
|
* __construct() -- private method
|
|
*
|
|
* this is the class constructor which is invoked from the singleton() class method.
|
|
*
|
|
* the constructor reads the services configuration from the gasConfig class and breaks out the relevant
|
|
* configurations by service assigning the data to class variables.
|
|
*
|
|
* we also initially mark all of the resource services as unavailable so as to require explicit initialization
|
|
* to the respective service via the fetchResource() method.
|
|
*
|
|
* last, we generate a GUID and assign it to a local member variable - this is done more as an intellectual
|
|
* exercise, rather than anything useful for the framework, to show that PHP really can't do statics.
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding
|
|
* 06-29-17 mks CORE-458: added mysql resources
|
|
* 09-12-17 mks CORE-561: replaced mysql resources with PDO resources
|
|
* 11-30-17 mks CORE-591: moved logger instantiation above resourceCheck() because that method
|
|
* calls debug logging
|
|
* 01-10-18 mks INF-147: fixed bug in PDO master resource check that prevented an error message from being
|
|
* logged on unsuccessful resource instantiation
|
|
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
|
* 06-15-18 mks HOTFIX: better logging, ddb active checks
|
|
* 07-27-18 mks CORE-1108: logging update - use logger if available for info messages
|
|
*
|
|
*/
|
|
private function __construct()
|
|
{
|
|
if (static::$available)return;
|
|
register_shutdown_function(array($this, '__destruct'));
|
|
|
|
// NOTE: DURING IPL, LOGGER IS NOT YET INSTANTIATED SO ERROR/CHECKPOINT OUTPUT GOES TO CONSOLE
|
|
|
|
// die if we cannot access the global error or config objects
|
|
if (empty(gasConfig::$settings)) {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, STRING_ERROR . ERROR_GCO_NA));
|
|
return;
|
|
}
|
|
|
|
static::$debug = intval(gasConfig::$settings[CONFIG_DEBUG]);
|
|
static::$debug = (static::$debug == 1 || static::$debug == 0) ? static::$debug : 0;
|
|
|
|
$this->class = get_class($this);
|
|
static::$cfgDdb = null;
|
|
static::$cfgBroker = null;
|
|
static::$cfgLogger = null;
|
|
static::$brokerAvailable = false;
|
|
static::$segundoAvailable = false;
|
|
static::$terceroAvailable = false;
|
|
static::$adminAvailable = false;
|
|
|
|
// copy the resource configuration blocks into their respective containers
|
|
if (!empty(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB][CONFIG_DATABASE_DDB_APPSERVER])) {
|
|
static::$cfgDdb = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB][CONFIG_DATABASE_DDB_APPSERVER];
|
|
} else {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_CONFIG_RESOURCE_404 . RESOURCE_DDB));
|
|
return;
|
|
}
|
|
if (!empty(gasConfig::$settings[CONFIG_SECURITY])) {
|
|
static::$cfgSecurity = gasConfig::$settings[CONFIG_SECURITY];
|
|
}
|
|
|
|
if (!empty(gasConfig::$settings[CONFIG_CACHE])) {
|
|
static::$cfgCache = gasConfig::$settings[CONFIG_CACHE];
|
|
}
|
|
if (!empty(gasConfig::$settings[CONFIG_BROKER_SERVICES])) {
|
|
static::$cfgBroker = gasConfig::$settings[CONFIG_BROKER_SERVICES];
|
|
static::$certPath = static::$cfgBroker[CONFIG_BROKER_CERT_PATH];
|
|
static::$certFile = static::$certPath . DIR_SSL_CLIENT . FILE_LOCAL_KEYCERT;
|
|
static::$caFile = static::$certPath . DIR_SSL_RMQ . FILE_CA_CERT;
|
|
}
|
|
|
|
if (!empty(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_PDO])) {
|
|
static::$cfgPDO = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_PDO];
|
|
static::$PDOEnabled = static::$cfgPDO[CONFIG_DATABASE_PDO_ENABLED];
|
|
}
|
|
|
|
if (!empty(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB])) {
|
|
static::$cfgMongo = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB];
|
|
static::$mongoEnabled = static::$cfgMongo[CONFIG_DATABASE_MONGODB_ENABLED];
|
|
}
|
|
|
|
if (!empty(gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_ADMIN])) {
|
|
static::$cfgAdmin = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_ADMIN];
|
|
}
|
|
|
|
if (!empty(gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_WH])) {
|
|
static::$cfgSegundo = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_WH];
|
|
}
|
|
|
|
// checkpoint
|
|
static::internalLog(INFO_CKP_CONFIG_LOADED);
|
|
|
|
try {
|
|
// all configs are loaded - instantiate the logger class for resourceCheck()
|
|
static::$logger = new gacErrorLogger();
|
|
// have to init the cache resource b/c PHP's faux statics...
|
|
@gasResourceManager::fetchResource(RESOURCE_CACHE);
|
|
// meat-n-taters part -- get/assign links to the external resources
|
|
if (!static::$resourcesChecked) {
|
|
static::resourceCheck();
|
|
static::$resourcesChecked = true;
|
|
}
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, 'resources checked and loaded'));
|
|
} catch (Throwable $t) {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage()));
|
|
return;
|
|
}
|
|
|
|
// validate the resource acquisitions and output the status of each
|
|
// DDB:
|
|
static::internalLog(sprintf(basename(__FILE__), __LINE__, 'Validating resources...'));
|
|
if (static::$cfgDdb[CONFIG_DATABASE_DDB_ENABLED] and !static::$ddbAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_DDB);
|
|
static::internalLog($msg);
|
|
return;
|
|
} elseif (static::$cfgDdb[CONFIG_DATABASE_DDB_ENABLED]) {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, RESOURCE_DDB . STUB_VALIDATED));
|
|
}
|
|
// Memcached:
|
|
if (!static::$cacheAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_CACHE);
|
|
static::internalLog($msg);
|
|
} else {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, RESOURCE_CACHE . STUB_VALIDATED));
|
|
}
|
|
// namaste primary "broker" is always required
|
|
if (!static::$brokerAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_BROKER);
|
|
static::internalLog($msg);
|
|
return;
|
|
} else {
|
|
static::internalLog(sprintf(basename(__FILE__), __LINE__, RESOURCE_BROKER . STUB_VALIDATED));
|
|
}
|
|
// namaste admin broker is always required
|
|
if (!static::$adminAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_ADMIN);
|
|
static::internalLog($msg);
|
|
return;
|
|
} else {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, RESOURCE_ADMIN . STUB_VALIDATED));
|
|
}
|
|
// namaste secondary service is optional
|
|
if (gasConfig::$settings[RESOURCE_SEGUNDO] === 1 and !static::$segundoAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_SEGUNDO);
|
|
static::internalLog($msg);
|
|
return;
|
|
} elseif (static::$segundoAvailable) {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, RESOURCE_SEGUNDO . STUB_VALIDATED));
|
|
}
|
|
if (gasConfig::$settings[RESOURCE_TERCERO] === 1 and !static::$terceroAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_TERCERO);
|
|
static::internalLog($msg);
|
|
return;
|
|
} elseif (static::$terceroAvailable) {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, RESOURCE_TERCERO . STUB_VALIDATED));
|
|
}
|
|
|
|
// for PDO, it's required only if PDO driver for mariaDB has been enabled
|
|
if (static::$PDOEnabled and !static::$PDOAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_PDO_MASTER);
|
|
static::internalLog($msg);
|
|
return;
|
|
} elseif (static::$PDOEnabled) {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, RESOURCE_PDO_MASTER . STUB_VALIDATED));
|
|
}
|
|
|
|
// same for mongo master - it's required only if it's been enabled for the current configuration
|
|
if (static::$mongoEnabled and !static::$mongoMasterAvailable) {
|
|
static::$IPL = false;
|
|
$msg = sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, ERROR_RESOURCE_404 . RESOURCE_MONGO_MASTER);
|
|
static::internalLog($msg);
|
|
return;
|
|
} elseif (static::$mongoEnabled) {
|
|
static::internalLog(sprintf(INFO_CKP_REACHED, basename(__FILE__), __LINE__, RESOURCE_MONGO_MASTER . STUB_VALIDATED));
|
|
}
|
|
static::internalLog('Resource load completed successfully......');
|
|
}
|
|
|
|
|
|
/**
|
|
* resourceCheck() -- private static method
|
|
*
|
|
* this method is called from the constructor function (only) and validates all that all of the necessary resources
|
|
* are available by instantiation.
|
|
*
|
|
* by default, all of the resources are initialized to false (not available) -- once a resource is instantiated,
|
|
* then we toggle the class static resource-availability variable to true.
|
|
*
|
|
* there are no input parameters or returns.
|
|
* resources are immediately (and properly) de-allocated.
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding
|
|
* 06-29-17 mks CORE-458: mysql resource support
|
|
* 07-02-17 mks CORE-464: mongo resource support
|
|
* 09-12-17 mks CORE-561: PDO resource support to replace mysql resource support
|
|
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
|
* 07-17-18 mks _INF-134: added console log messages to help with deployment/first-run diagnostics
|
|
* 07-24-18 mks CORE-1099: deprecating mongo slave resource use
|
|
* 07-27-18 mks CORE-1108: console logging alternative (use logging if available)
|
|
*
|
|
*/
|
|
private static function resourceCheck()
|
|
{
|
|
try {
|
|
if (intval(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB][CONFIG_DATABASE_DDB_ENABLED]) == 1) {
|
|
static::internalLog(INFO_FETCHING_RESOURCE . RESOURCE_DDB);
|
|
@static::fetchResource(RESOURCE_DDB);
|
|
}
|
|
|
|
static::internalLog(INFO_FETCHING_RESOURCE . RESOURCE_CACHE);
|
|
/** @var memcached $c */
|
|
@static::fetchResource(RESOURCE_CACHE);
|
|
if (!static::$cacheAvailable) {
|
|
consoleLog(static::$myID, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_CACHE);
|
|
}
|
|
|
|
if (static::$cfgPDO[CONFIG_DATABASE_PDO_ENABLED]) {
|
|
static::internalLog(INFO_FETCHING_RESOURCE . RESOURCE_PDO_MASTER);
|
|
@static::fetchResource(RESOURCE_PDO_MASTER);
|
|
if (!static::$PDOAvailable) {
|
|
consoleLog(static::$myID, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_PDO_MASTER);
|
|
}
|
|
}
|
|
if (static::$cfgMongo[CONFIG_DATABASE_MONGODB_ENABLED]) {
|
|
static::internalLog(INFO_FETCHING_RESOURCE . RESOURCE_MONGO_MASTER);
|
|
@static::fetchResource(RESOURCE_MONGO_MASTER);
|
|
if (!static::$mongoMasterAvailable)
|
|
consoleLog(static::$myID, CON_ERROR, ERROR_RESOURCE_404 . RESOURCE_MONGO_MASTER);
|
|
}
|
|
|
|
foreach (static::$brokerServices as $brokerService) {
|
|
if (isset(gasConfig::$settings[CONFIG_BROKER_SERVICES][$brokerService]) and is_array(gasConfig::$settings[CONFIG_BROKER_SERVICES][$brokerService])) {
|
|
static::internalLog(INFO_FETCHING_RESOURCE . $brokerService);
|
|
$r = static::fetchResource($brokerService);
|
|
if (!is_object($r)) {
|
|
$msg = ERROR_RESOURCE_404 . $brokerService;
|
|
if (!is_null(static::$logger) and static::$logger->available) {
|
|
static::$logger->fatal($msg);
|
|
}
|
|
consoleLog(static::$myID, CON_ERROR, '(' . __LINE__ . ')' . $msg);
|
|
}
|
|
unset($r);
|
|
}
|
|
}
|
|
} catch (Throwable $t) {
|
|
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
|
$msg = ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
|
static::internalLog($hdr . $msg);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* fetchResource() -- public static method
|
|
*
|
|
* this is the method used to fetch resources objects for the various end-points (nosql, rabbit, cache, etc.)
|
|
*
|
|
* the input parameter to the method defines, by constant, which resource to fetch.
|
|
*
|
|
* Because the various resources are varying types, (resource, object, http-connection, etc.), the responsibility
|
|
* on validating the return type is on the client. If the resource could not be attained, or the request was
|
|
* improper, then we're going to return a null value to the calling client.
|
|
*
|
|
* Programmer's Notes:
|
|
* -------------------
|
|
* This method is called from the constructor so, at first glance, it may seem odd that we're explicitly returning
|
|
* static variables within the class -- however, this method is also used within the framework for ad-hoc resource
|
|
* requests which is why we're explicitly returning the static. That, and also if PHP ever does truly support
|
|
* true/pure static classes, then we'll be ready.
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @param string $_resourceType
|
|
* @param string $_location -- only used by gacLogger class
|
|
* @return null|object
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding (estimate)
|
|
* 07-13-17 mks updated for service locations
|
|
* 09-12-17 mks CORE-561: PDO driver replaces mysqli
|
|
* 04-11-18 mks _INF_188: refactored for segundo broker (warehousing), typeError trapping, better logging
|
|
* 07-24-18 mks CORE-1099: deprecated mongodb slave resource use
|
|
* 08-28-18 mks DB-50: lite initialization support
|
|
* 07-29-20 mks DB-156: tercero support
|
|
*
|
|
*/
|
|
public static function fetchResource(string $_resourceType, string $_location = ENV_APPSERVER): ?object
|
|
{
|
|
try {
|
|
switch ($_resourceType) {
|
|
case RESOURCE_DDB : // we do not return a resource - just a connection to the remote http service
|
|
static::getDdbResource();
|
|
return static::$resDdb;
|
|
break;
|
|
// RabbitMQ Broker Resources (not database)
|
|
case RESOURCE_ADMIN :
|
|
case RESOURCE_BROKER :
|
|
case RESOURCE_SEGUNDO :
|
|
case RESOURCE_TERCERO :
|
|
try {
|
|
return (static::getBrokerResource($_resourceType));
|
|
} catch (TypeError $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_TYPE_EXCEPTION;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
break;
|
|
case RESOURCE_PDO_MASTER :
|
|
// check, for lite initialization, if the config has been loaded
|
|
if (empty(static::$cfgPDO) and !static::$resourcesChecked) {
|
|
static::$cfgPDO = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_PDO];
|
|
if (empty(static::$cfgPDO)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_CONFIG_RESOURCE_404 . CONFIG_DATABASE_PDO;
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
}
|
|
// resource must be "turned on" in the XML config otherwise reject the request
|
|
if (1 != static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][STRING_ENABLED]) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_RESOURCE_404 . RESOURCE_PDO_MASTER;
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
if (is_object(static::$resPDO) and static::$PDOAvailable) return static::$resPDO;
|
|
try {
|
|
static::$resPDO = static::getPDOResourceMaster(ENV_APPSERVER);
|
|
static::$PDOAvailable = (is_null(static::$resPDO)) ? false : true;
|
|
return static::$resPDO;
|
|
} catch (TypeError $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_TYPE_EXCEPTION;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
break;
|
|
case RESOURCE_WH_COOL_PDO_MASTER :
|
|
// resource must be "turned on" in the XML config otherwise reject the request
|
|
if (1 != static::$cfgPDO[CONFIG_COOL_STORAGE][STRING_ENABLED]) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_RESOURCE_404 . RESOURCE_WH_COOL_PDO_MASTER;
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
try {
|
|
static::$resPDOWHMaster = static::getPDOResourceMaster(ENV_SEGUNDO);
|
|
static::$PDOWHMasterAvailable = (is_null(static::$resPDOWHMaster)) ? false : true;
|
|
return static::$resPDOWHMaster;
|
|
} catch (TypeError $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_TYPE_EXCEPTION;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
break;
|
|
case RESOURCE_PDO_SECONDARY :
|
|
if (empty(static::$cfgPDO) and !static::$resourcesChecked) {
|
|
static::$cfgPDO = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_PDO];
|
|
if (empty(static::$cfgPDO)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_CONFIG_RESOURCE_404 . CONFIG_DATABASE_PDO;
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
}
|
|
// resource must be "turned on" in the XML config otherwise reject the request
|
|
if (1 != static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][STRING_ENABLED]) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_RESOURCE_404 . RESOURCE_PDO_SECONDARY;
|
|
static::internalLog($msg);
|
|
return null;
|
|
} elseif (isset(static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_USE_SECONDARY]) and 1 != static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_USE_SECONDARY]) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_PDO_SLAVE;
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
if (is_object(static::$resPDOSlave) and static::$PDOSlaveAvailable) return static::$resPDOSlave;
|
|
try {
|
|
static::$resPDOSlave = static::getPDOResourceSlave(ENV_APPSERVER);
|
|
static::$PDOSlaveAvailable = (is_null(static::$resPDOSlave)) ? false : true;
|
|
return static::$resPDOSlave;
|
|
} catch (TypeError $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_TYPE_EXCEPTION;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
break;
|
|
case RESOURCE_MONGO_MASTER :
|
|
try {
|
|
static::$location = $_location;
|
|
switch (static::$location) {
|
|
case ENV_APPSERVER :
|
|
static::getMongoResource(MONGO_MASTER);
|
|
return static::$resMongoMaster;
|
|
break;
|
|
case ENV_ADMIN :
|
|
static::getMongoResource(MONGO_ADMIN_MASTER);
|
|
return static::$resMongoAdminMaster;
|
|
break;
|
|
case ENV_SEGUNDO :
|
|
static::getMongoResource(MONGO_SEGUNDO_MASTER);
|
|
return static::$resMongoSegundoMaster;
|
|
break;
|
|
case ENV_TERCERO :
|
|
static::getMongoResource(MONGO_TERCERO_MASTER);
|
|
return static::$resMongoTerceroMaster;
|
|
break;
|
|
default :
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_ENV_INVALID . static::$location;
|
|
static::internalLog($msg);
|
|
return null;
|
|
break;
|
|
}
|
|
} catch (Throwable | TypeError $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_TYPE_EXCEPTION;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
break;
|
|
case RESOURCE_CACHE :
|
|
static::$resCache = gasCache::singleton();
|
|
if (is_object(static::$resCache))
|
|
static::$cacheAvailable = true;
|
|
return static::$resCache;
|
|
break;
|
|
default:
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_RESOURCE_TYPE_UNDEF, $_resourceType);
|
|
static::internalLog($msg);
|
|
break;
|
|
}
|
|
} catch (Throwable $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), $t->getLine()) . ERROR_THROWABLE_EXCEPTION;
|
|
static::internalLog($msg);
|
|
static::internalLog(sprintf(FAIL_RESOURCE_LOAD, $_resourceType, $_location));
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* reconnect() -- public method
|
|
*
|
|
* This method requires one input parameter - the named resource that we'll attempt to reconnect to.
|
|
*
|
|
* When we lose a resource connection, we'll call this method so that we can log the dropped-resource event.
|
|
*
|
|
* todo: make logging a system event
|
|
*
|
|
* This is a pass-through method to fetchResource() (in this class); this method is the preferred method for
|
|
* re-establishing a dropped-resource connection because of the information logging.
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @param string $_resource -- a well-defined Namaste resource
|
|
* @return null|object -- returns the PDO resource on success, null on error
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 01-16-18 mks CORE-697: original coding
|
|
*
|
|
*/
|
|
public static function reconnect(string $_resource)
|
|
{
|
|
static::internalLog(sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_PDO_RECONNECT);
|
|
try {
|
|
return (static::fetchResource($_resource));
|
|
} catch (TypeError $t) {
|
|
static::internalLog(sprintf(INFO_LOC,basename(__FILE__), __LINE__, ERROR_TYPE_EXCEPTION));
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* getDdbResource() -- private method
|
|
*
|
|
* reads the current configuration for the no-sql (Dynamo DB) resource and, if not set, will open a (HTTP)
|
|
* connection to the resource as defined in the xml configuration.
|
|
*
|
|
* Calculated values are implicitly returned to the calling client via class member population.
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding
|
|
*
|
|
*/
|
|
private static function getDdbResource()
|
|
{
|
|
$config = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB][CONFIG_DATABASE_DDB_APPSERVER];
|
|
$endpoint = $config[CONFIG_DATABASE_DDB_DSN] . ':' . $config[CONFIG_DATABASE_DDB_PORT];
|
|
$region = $config[CONFIG_DATABASE_DDB_REGION];
|
|
$version = $config[CONFIG_DATABASE_DDB_VERSION];
|
|
$credentials = [
|
|
STRING_KEY => $config[CONFIG_DATABASE_DDB_KEY_ID],
|
|
STRING_SECRET => $config[CONFIG_DATABASE_DDB_ACCESS_KEY]
|
|
];
|
|
if (is_null(static::$resDdb)) {
|
|
try {
|
|
// connect to the aws sdk
|
|
$awsSDK = new Aws\Sdk([
|
|
STRING_ENDPOINT => $endpoint,
|
|
STRING_REGION => $region,
|
|
STRING_CREDS => $credentials,
|
|
STRING_VERSION => $version
|
|
]);
|
|
// todo -- what does this return and can we trap an error?
|
|
static::$ddbAvailable = true;
|
|
static::$resDdb = $awsSDK->createDynamoDb();
|
|
} catch (Aws\Exception\AwsException | Throwable $t) {
|
|
static::internalLog(sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_DDB_INSTANTIATE);
|
|
static::internalLog($t->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* getBrokerResource() -- private static function
|
|
*
|
|
* this method initializes a connection to the RabbitMQ service as defined in the configuration file(s) and
|
|
* establishes the broker availability and resource.
|
|
*
|
|
* there is an input parameter to the method which is the name of which broker resource we're going to initialize.
|
|
* These tags are limited, at the time this method was written, to the following:
|
|
*
|
|
* BROKER -- unimaginative name which indicates the local, primary, namaste AMQP resource
|
|
* SEGUNDO -- the second (optional) namaste resource, a remote namaste instance
|
|
* TERCERO -- the third (optional) namaste resource, also a remote instance
|
|
* ADMIN -- the namaste administrative service which could also be a remote instance
|
|
*
|
|
* first step is to evaluate which configuration was passed so we can load the appropriate configuration (XML)
|
|
* in the correct container. If an invalid config was passed, record the error and return a Boolean(false).
|
|
*
|
|
* next, load-up the basic access-data values (x5) from the current configuration...
|
|
*
|
|
* next, check to see if the current configuration requires an SSL connection to the resource. If it does,
|
|
* make a quick check to ensure that the certificate files are accessible by namaste and then attempt to
|
|
* make the SSL connection.
|
|
*
|
|
* If the config does not require SSL, make a non-SSL connection. (Note: we're using AMQPStreamConnection for
|
|
* the first time instead of the generic AMQPConnection type.) Also, because of an inherent PHP bug, only
|
|
* pass-in the heartbeat and the keep-alive options for the non-SSL connection.
|
|
*
|
|
* todo -- see if the SSL heartbeat and keepalive bugs were fixed in PHP7.0
|
|
*
|
|
* the connect request is exception wrapped and will post a log message
|
|
*
|
|
* On successful connect, we mark the resource as available, otherwise error messages are sent and the resource
|
|
* is explicitly marked as unavailable prior to returning.
|
|
*
|
|
* PROGRAMMER NOTES:
|
|
* -----------------
|
|
* In previous incarnations of this module, there were explicit connector methods for each type of broker
|
|
* resource. This incarnation deprecates the separate methods as all four broker resources are now initialized
|
|
* by this single method. Progress.
|
|
*
|
|
*
|
|
* @param string $_config
|
|
* @return bool|AMQPStreamConnection|AMQPStreamConnection
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding
|
|
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
|
*
|
|
*/
|
|
private static function getBrokerResource(string $_config)
|
|
{
|
|
$rabbitResource = false;
|
|
$options = null;
|
|
$currentConfig = null;
|
|
|
|
if (!empty(gasConfig::$settings[CONFIG_BROKER_SERVICES][$_config])) {
|
|
switch ($_config) {
|
|
case CONFIG_BROKER_APPSERVER:
|
|
static::$cfgBroker = gasConfig::$settings[CONFIG_BROKER_SERVICES][$_config];
|
|
$currentConfig = static::$cfgBroker;
|
|
break;
|
|
case CONFIG_BROKER_WH:
|
|
static::$cfgSegundo = gasConfig::$settings[CONFIG_BROKER_SERVICES][$_config];
|
|
$currentConfig = static::$cfgSegundo;
|
|
break;
|
|
case CONFIG_BROKER_TERCERO:
|
|
static::$cfgTercero = gasConfig::$settings[CONFIG_BROKER_SERVICES][$_config];
|
|
$currentConfig = static::$cfgTercero;
|
|
break;
|
|
case CONFIG_ADMIN:
|
|
static::$cfgAdmin = gasConfig::$settings[CONFIG_BROKER_SERVICES][$_config];
|
|
$currentConfig = static::$cfgAdmin;
|
|
break;
|
|
default:
|
|
$msg = sprintf(basename(__FILE__), __LINE__) . ERROR_BROKER_TYPE_UNDEF . $_config;
|
|
static::internalLog($msg);
|
|
return false;
|
|
break;
|
|
}
|
|
} else {
|
|
$rabbitResource = false;
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_CONFIG_RESOURCE_404 . $_config;
|
|
static::internalLog($msg);
|
|
return $rabbitResource;
|
|
}
|
|
|
|
if (!empty($currentConfig)) { // ensure we have a broker configuration...
|
|
$user = $currentConfig[STRING_USER]; // and load the basic MQ connection params
|
|
$pass = $currentConfig[STRING_PASS];
|
|
$host = $currentConfig[STRING_HOST];
|
|
$port = $currentConfig[STRING_PORT];
|
|
$vhost = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_VHOST];
|
|
if (gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_USE_SSL] and gasConfig::$settings[CONFIG_SECURITY][CONFIG_SECURITY_REQUIRES_TLS][CONFIG_SECURITY_REQUIRES_TLS_MQ] == 1) {
|
|
try {
|
|
// if the configuration requires SSL, make a secure connection to the resource.
|
|
if (!static::checkCerts()) return false;
|
|
// build the ssl-options array and request a broker resource from the resource manager
|
|
$ssl_opts = [STRING_CA_FILE => static::$caFile, STRING_LOCAL_CERT => static::$certFile];
|
|
$rabbitResource = new AMQPSSLConnection($host, $port, $user, $pass, $vhost, $ssl_opts, $options);
|
|
} catch (Throwable $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_RESOURCE_404 . RESOURCE_BROKER;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
return false;
|
|
}
|
|
} else {
|
|
// non-ssl broker connection
|
|
try {
|
|
$tv = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_TIMER_VIOLATION];
|
|
$ka = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_KEEP_ALIVE];
|
|
$ka = ($ka === 1) ? true : false;
|
|
$hb = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_HEARTBEAT];
|
|
|
|
$rabbitResource = new AMQPStreamConnection($host, $port, $user, $pass, $vhost, false,
|
|
STRING_AMQPLAIN, null, LOCALE, $tv, $tv, null, $ka, $hb);
|
|
} catch (Throwable $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_RESOURCE_404 . RESOURCE_BROKER;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
switch ($_config) {
|
|
case CONFIG_BROKER_APPSERVER:
|
|
static::$brokerAvailable = is_object($rabbitResource);
|
|
static::$resBroker = $rabbitResource;
|
|
break;
|
|
case CONFIG_BROKER_WH:
|
|
static::$segundoAvailable = is_object($rabbitResource);
|
|
static::$resSegundo = $rabbitResource;
|
|
break;
|
|
case CONFIG_BROKER_TERCERO:
|
|
static::$terceroAvailable = is_object($rabbitResource);
|
|
static::$resTercero = $rabbitResource;
|
|
break;
|
|
case CONFIG_ADMIN:
|
|
static::$adminAvailable = is_object($rabbitResource);
|
|
static::$resAdmin = $rabbitResource;
|
|
break;
|
|
}
|
|
return $rabbitResource;
|
|
}
|
|
|
|
|
|
/**
|
|
* checkCerts() -- private static method
|
|
*
|
|
* this method was embedded in the resource-initialization method for starting a broker -- since we can now
|
|
* use this code twice (once for the localhost broker and once for the localhost vault), it was broken out
|
|
* into a private method and improved a bit.
|
|
*
|
|
* basically the method just checks to see if the key-cert and ca files are accessible. if they both are,
|
|
* then the method will return a Boolean(true). If either, or both, are not available, then a Boolean(false)
|
|
* is return and an error message is written to the console and, if available, to the global log file.
|
|
*
|
|
* There are no inputs to the method.
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @return bool
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-26-15 mks original coding
|
|
*
|
|
*/
|
|
private static function checkCerts(): bool
|
|
{
|
|
$goodCerts = false;
|
|
$pass1 = false;
|
|
|
|
// verify that we can "see" the ssl client key-cert file
|
|
if (!file_exists(static::$certFile)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . STRING_ERROR . ERROR_FILE_404 . static::$certFile;
|
|
static::internalLog($msg);
|
|
} else {
|
|
$pass1 = true;
|
|
}
|
|
|
|
// verify that we can "see" the certificate-authority file
|
|
if (!file_exists(static::$caFile)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . STRING_ERROR . ERROR_FILE_404 . static::$caFile;
|
|
static::internalLog($msg);
|
|
} elseif ($pass1) {
|
|
$goodCerts = true;
|
|
}
|
|
return $goodCerts;
|
|
}
|
|
|
|
|
|
/**
|
|
* getPDOResourceMaster() -- private static method
|
|
*
|
|
* this method checks to see if a mysql-pdo master resource exists and, if not, creates one.
|
|
*
|
|
* errors encountered are logged as fatals and the PDO-Master availability is set to false, and the
|
|
* PDO resource is set to null.
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @param string $_which -- mandatory and must be defined as ENV_PRIME, ENV_SEGUNDO or ENV_TERCERO
|
|
* @return null|PDO
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* --------
|
|
* 06-29-17 mks original coding
|
|
* 08-17-17 mks CORE-561: in with PDO, out with mysqli
|
|
* 05-07-18 mks _INF-188: WH support, PHP7 header, explicit return
|
|
*
|
|
*/
|
|
private static function getPDOResourceMaster(string $_which): ?PDO
|
|
{
|
|
$PDOResource = null;
|
|
$validEnvs = [ ENV_APPSERVER, ENV_SEGUNDO, ENV_TERCERO ];
|
|
if (!in_array($_which, $validEnvs)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_RESOURCE_TYPE_UNDEF, $_which);
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
|
|
// exit if we've not loaded a the PDO configuration
|
|
if (empty(static::$cfgPDO)) {
|
|
$msg = sprintf(basename(__FILE__), __LINE__) . ERROR_CONFIG_RESOURCE_404 . RESOURCE_PDO_MASTER;
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
|
|
// qualify and populate based on the environment requested
|
|
|
|
// "default" settings are for ENV_PRIME (namaste)
|
|
$namastePDO = static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_MASTER];
|
|
$db = 'dbname=' . gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $namastePDO[CONFIG_DATABASE_PDO_DB];
|
|
switch ($_which) {
|
|
case ENV_APPSERVER :
|
|
if (static::$resourcesChecked and static::$PDOAvailable and !is_null(static::$resPDO)) {
|
|
// if services are already flagged as available, query the PDO resource to confirm
|
|
static::$PDOAvailable = (is_null(static::$resPDO->getAttribute(PDO::ATTR_CONNECTION_STATUS))) ? false : true;
|
|
if (static::$PDOAvailable) return static::$resPDO;
|
|
}
|
|
break;
|
|
case ENV_SEGUNDO :
|
|
if (static::$PDOWHMasterAvailable and !is_null(static::$resPDOWHMaster)) {
|
|
static::$PDOWHMasterAvailable = (is_null(static::$resPDOWHMaster->getAttribute(PDO::ATTR_CONNECTION_STATUS))) ? false : true;
|
|
if (static::$PDOWHMasterAvailable) return static::$resPDOWHMaster;
|
|
}
|
|
$namastePDO = static::$cfgPDO[CONFIG_COOL_STORAGE][CONFIG_DATABASE_PDO_MASTER];
|
|
$db = 'dbname=' . gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $namastePDO[CONFIG_DATABASE_PDO_DB];
|
|
break;
|
|
}
|
|
|
|
$pdoAttributes = [
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => 1,
|
|
// PDO::ATTR_PERSISTENT => true,
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
|
|
];
|
|
|
|
// if we failed to verify the connection, we've marked the availability as false, fall-thru and attempt to reconnect
|
|
// if ((!static::$PDOAvailable) and static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_ENABLED]) {
|
|
$host = $namastePDO[CONFIG_DATABASE_PDO_HOSTNAME];
|
|
$user = $namastePDO[CONFIG_DATABASE_PDO_USERNAME];
|
|
$pass = $namastePDO[CONFIG_DATABASE_PDO_PASSWORD];
|
|
$port = $namastePDO[CONFIG_DATABASE_PDO_PORT];
|
|
|
|
// connect to mariaDB
|
|
$PDOConnectString = 'mysql:host=' . $host . COLON_NS . $port . SEMI . $db . SEMI . $namastePDO[CONFIG_DATABASE_PDO_CHARSET];
|
|
if (static::$debug) static::$logger->debug('PDO-Connection: ' . $PDOConnectString);
|
|
try {
|
|
$PDOResource = new PDO($PDOConnectString, $user, $pass, $pdoAttributes);
|
|
} catch (PDOException | Throwable $e) {
|
|
if (isset(static::$logger) and static::$logger->available) {
|
|
static::$logger->fatal(ERROR_PDO_CONNECT);
|
|
static::$logger->fatal($e->getMessage());
|
|
}
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_PDO_CONNECT;
|
|
static::internalLog($msg);
|
|
static::internalLog($e->getMessage());
|
|
return null;
|
|
}
|
|
// }
|
|
return $PDOResource;
|
|
}
|
|
|
|
|
|
/**
|
|
* getPDOResourceSlave() -- private static method
|
|
*
|
|
* this method checks to see if a mysql-pdo slave resource exists and, if not, creates one.
|
|
*
|
|
* errors encountered are logged as fatals and the PDO-Slave availability is set to false, and the
|
|
* PDO resource is set to null.
|
|
*
|
|
* https://secure.php.net/manual/en/mysqlnd-ms.quickstart.usage.php
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @param string $_env
|
|
* @return null|PDO
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* --------
|
|
* 09-15-17 mks CORE-562: original coding
|
|
* 05-07-18 mks _INF-188: WH Support, PHP7 Header, explicit resource return
|
|
*
|
|
*/
|
|
private static function getPDOResourceSlave(string $_env = ENV_APPSERVER): ? PDO
|
|
{
|
|
$PDOResource = null;
|
|
$validEnvs = [ ENV_APPSERVER, ENV_SEGUNDO, ENV_TERCERO ];
|
|
if (!in_array($_env, $validEnvs)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_RESOURCE_TYPE_UNDEF, $_env);
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
|
|
// exit if we've not loaded a the PDO configuration
|
|
if (empty(static::$cfgPDO)) {
|
|
$msg = sprintf(basename(__FILE__), __LINE__) . ERROR_CONFIG_RESOURCE_404 . RESOURCE_PDO_MASTER;
|
|
static::internalLog($msg);
|
|
static::$PDOSlaveAvailable = false;
|
|
static::$resPDOSlave = null;
|
|
return null;
|
|
}
|
|
|
|
// qualify and populate based on the environment requested
|
|
|
|
// "default" settings are for ENV_PRIME (namaste)
|
|
$slaveCFG = static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_SECONDARY];
|
|
$dbName = static::$cfgPDO[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_MASTER][CONFIG_DATABASE_PDO_DB];
|
|
$db = 'dbname=' . gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $dbName;
|
|
switch ($_env) {
|
|
case ENV_APPSERVER :
|
|
if (static::$PDOSlaveAvailable and !is_null(static::$resPDOSlave)) {
|
|
// if services are already flagged as available, query the PDO resource to confirm
|
|
static::$PDOSlaveAvailable = (is_null(static::$resPDOSlave->getAttribute(PDO::ATTR_CONNECTION_STATUS))) ? false : true;
|
|
if (static::$PDOSlaveAvailable) return static::$resPDOSlave;
|
|
}
|
|
break;
|
|
case ENV_SEGUNDO :
|
|
if (static::$PDOWHSlaveAvailable and !is_null(static::$resPDOWHSlave)) {
|
|
static::$PDOWHSlaveAvailable = (is_null(static::$resPDOWHSlave->getAttribute(PDO::ATTR_CONNECTION_STATUS))) ? false : true;
|
|
if (static::$PDOWHSlaveAvailable) return static::$resPDOWHSlave;
|
|
}
|
|
$slaveCFG = static::$cfgPDO[CONFIG_COOL_STORAGE][CONFIG_DATABASE_PDO_SECONDARY];
|
|
$dbName = static::$cfgPDO[CONFIG_COOL_STORAGE][CONFIG_DATABASE_PDO_MASTER][CONFIG_DATABASE_PDO_DB];
|
|
$db = 'dbname=' . gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $dbName;
|
|
break;
|
|
}
|
|
|
|
$pdoAttributes = [
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
// PDO::ATTR_PERSISTENT => true,
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::FETCH_ASSOC => PDO::FETCH_ASSOC
|
|
];
|
|
|
|
// check to see if the PDO read-slave service is enabled and, if so, connect.
|
|
$host = $slaveCFG[CONFIG_DATABASE_PDO_HOSTNAME];
|
|
$user = $slaveCFG[CONFIG_DATABASE_PDO_USERNAME];
|
|
$pass = $slaveCFG[CONFIG_DATABASE_PDO_PASSWORD];
|
|
$port = $slaveCFG[CONFIG_DATABASE_PDO_PORT];
|
|
$PDOConnectString = 'mysql:host=' . $host . COLON_NS . $port . SEMI . $db . SEMI . $slaveCFG[CONFIG_DATABASE_PDO_CHARSET];
|
|
if (static::$debug) static::$logger->debug('PDO-Connection: ' . $PDOConnectString);
|
|
|
|
try {
|
|
$PDOResource = new PDO($PDOConnectString, $user, $pass, $pdoAttributes);
|
|
} catch (PDOException | Throwable $e) {
|
|
if (isset(static::$logger) and static::$logger->available) {
|
|
static::$logger->fatal(ERROR_PDO_CONNECT);
|
|
static::$logger->fatal($e->getMessage());
|
|
} else {
|
|
static::internalLog(sprintf(basename(__FILE__), __LINE__) . ERROR_PDO_CONNECT);
|
|
static::internalLog($e->getMessage());
|
|
}
|
|
return null;
|
|
}
|
|
return $PDOResource;
|
|
}
|
|
|
|
|
|
/**
|
|
* getMongoResource() -- private method
|
|
*
|
|
* the method has an optional parameter which establishes the target resource as being either the mongo master
|
|
* (default) the mongo slave, the mongo WH master, or the mongo WH slave.
|
|
*
|
|
* A second, also optional, parameter is only used for warehousing resources -- specifies the level of
|
|
* warehousing (COOL, COLD, WARM, etc.) and this is used to ensure we're pulling the correct XML section
|
|
* from the configuration.
|
|
*
|
|
* this method checks to see if a mongo-configuration exists, and if so, has the mongo service been enabled. If
|
|
* the former is missing, or the latter is not enabled, then post an error and return;
|
|
*
|
|
* continue by scraping the XML configuration to build the connectivity string that we'll pass to the MongoDB
|
|
* Manager driver. Include the replSet configuration if enabled.
|
|
*
|
|
* We attempt to connect to the mongo service and store the connection resource as a class property object.
|
|
* The connection attempt is exception wrapped so any failures will be recorded.
|
|
*
|
|
* A successful connection will set the class property $resMongoMaster to the mongo resource whereas any error
|
|
* will result in this value being set to null.
|
|
*
|
|
* A successful connection will set the class property $mongoMasterAvailable to Boolean(true) whereas any error
|
|
* will result in this value being set to Boolean(false).
|
|
*
|
|
* Programmer's Notes:
|
|
* -------------------
|
|
* as of now, there's no support coded for SSL connectivity
|
|
* user passwords are located in the database specified in the XML file which may not be the current db
|
|
*
|
|
* the only difference between a master and a slave (read-only) connection for mongo is the readPreference
|
|
* setting in the $options array.
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @param string $_which -- indicates resource allocation for either master or slave defaulting to master
|
|
* @param string $_whLevel -- should be either COOL, COLD, or WARM or HOT
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 07-05-17 mks CORE-464: original coding
|
|
* 07-13-17 mks support for multiple locations (namaste, admin, etc.)
|
|
* updated exception handling for PHP 7
|
|
* 10-02-17 mks CORE-572: updated mongo read-preferences for 3.2.17, exception logging
|
|
* 11-27-17 mks CORE-635: sharded-cluster, repl-set, stand-alone instance connection options
|
|
* 05-05-18 mks _INF-188: support for mongo WH resources, converted error messaging to console log method
|
|
* 07-03-18 mks CORE-1053: testing a successful mongoDB connection
|
|
* 08-24-18 mks CORE-1097: refactoring mongo resources (RBAC, RP)
|
|
* 08-24-18 mks CORE-1099: deprecation mongodb slave resource handling
|
|
* 08-28-18 mks DB-50: lite configuration (no bootstrap) support
|
|
* 07-29-20 mks DB-156: tercero support
|
|
* 12-10-20 mks DB-180: support for segundo (non warehousing broker)
|
|
*
|
|
*/
|
|
private static function getMongoResource(string $_which = MONGO_MASTER, string $_whLevel = ''): void
|
|
{
|
|
// todo - system table for these variables
|
|
$validLocations = [ ENV_APPSERVER, ENV_ADMIN, ENV_SEGUNDO, ENV_TERCERO ];
|
|
$validWHLevels = [ WH_TYPE_COOL, WH_TYPE_HOT, WH_TYPE_WARM, WH_TYPE_COLD ];
|
|
$validWhich = [ MONGO_MASTER, MONGO_WH_MASTER, MONGO_SEGUNDO_MASTER, MONGO_ADMIN_MASTER, MONGO_TERCERO_MASTER ];
|
|
$errors = [];
|
|
|
|
// validate the which param
|
|
if (!in_array($_which, $validWhich)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_MONGO_RESOURCE_INVALID, $_which);
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
|
|
// is set, validate the wh-level
|
|
if (!empty($_whLevel) and !in_array($_whLevel, $validWHLevels)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_MONGO_WH_LEVEL_INVALID, $_whLevel);
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
|
|
// validate which mongo service location
|
|
if (!in_array(static::$location, $validLocations)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_MONGO_LOCATION_INVALID, static::$location);
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
|
|
// cannot continue without a mongo configuration -- if not set (lite initialization) then attempt to load
|
|
if (empty(static::$cfgMongo)) {
|
|
$msg = '';
|
|
// attempt to reload the config
|
|
if (!empty(gasConfig::$settings[CONFIG_DATABASE])) {
|
|
static::$cfgMongo = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB];
|
|
if (empty(static::$cfgMongo))
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_CONFIG_RESOURCE_404 . RESOURCE_MONGO_MASTER;
|
|
} else {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_CONFIG_RESOURCE_404 . RESOURCE_MONGO_MASTER;
|
|
}
|
|
if (strlen($msg)) {
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// validate that the service config exists
|
|
if (empty(static::$cfgMongo[static::$location])) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_MONGO_LOCATION_DNE, static::$location);
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
|
|
// validate that the requested env been enabled in the configuration
|
|
if (static::$location == ENV_SEGUNDO and $_which == MONGO_WH_MASTER) {
|
|
if (empty($_whLevel)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_MONGO_WH_LEVEL_404;
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
switch ($_whLevel) {
|
|
case WH_TYPE_COOL :
|
|
static::$location = CONFIG_COOL_STORAGE;
|
|
break;
|
|
case WH_TYPE_COLD :
|
|
static::$location = CONFIG_COLD_STORAGE;
|
|
break;
|
|
case WH_TYPE_WARM :
|
|
static::$location = CONFIG_WARM_STORAGE;
|
|
break;
|
|
case WH_TYPE_HOT :
|
|
static::$location = CONFIG_HOT_STORAGE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (intval(static::$cfgMongo[static::$location][CONFIG_DATABASE_MONGODB_ENABLED]) !== 1) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_MONGO_NOT_ENABLED, static::$location);
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
|
|
// validate which mongo node to connect to and reset those resources
|
|
switch ($_which) {
|
|
case MONGO_MASTER :
|
|
static::$resMongoMaster = null;
|
|
static::$mongoMasterAvailable = false;
|
|
$service = ENV_APPSERVER;
|
|
break;
|
|
case MONGO_SEGUNDO_MASTER :
|
|
static::$resMongoSegundoMaster = null;
|
|
static::$mongoSegundoMasterAvailable = false;
|
|
$service = ENV_SEGUNDO;
|
|
break;
|
|
case MONGO_WH_MASTER :
|
|
static::$resMongoWHMaster = null;
|
|
static::$mongoWHMasterAvailable = false;
|
|
$service = ENV_SEGUNDO;
|
|
break;
|
|
case MONGO_ADMIN_MASTER :
|
|
if (intval(gasConfig::$settings[ENV_ADMIN][CONFIG_ACTIVE]) !== 1) {
|
|
if (isset(static::$logger) and static::$logger->available) {
|
|
$msg = sprintf(INFO_LOC, basename(__METHOD__), __LINE__) . ERROR_ADMIN_NOT_ENABLED;
|
|
static::internalLog($msg);
|
|
}
|
|
return;
|
|
}
|
|
if (static::$location != ENV_ADMIN) static::$location = ENV_ADMIN;
|
|
static::$resMongoAdminMaster = null;
|
|
static::$mongoAdminMasterAvailable = false;
|
|
$service = ENV_ADMIN;
|
|
break;
|
|
case MONGO_TERCERO_MASTER :
|
|
if (intval(gasConfig::$settings[CONFIG_BROKER_TERCERO][CONFIG_ACTIVE]) !== 1) {
|
|
if (isset(static::$logger) and static::$logger->available) {
|
|
$msg = sprintf(INFO_LOC, basename(__METHOD__), __LINE__) . ERROR_TERCERO_NOT_ENABLED;
|
|
static::internalLog($msg);
|
|
}
|
|
return;
|
|
}
|
|
if (static::$location != ENV_TERCERO) static::$location = ENV_TERCERO;
|
|
static::$resMongoTerceroMaster = null;
|
|
static::$mongoTerceroMasterAvailable = false;
|
|
$service = ENV_TERCERO;
|
|
break;
|
|
default :
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_SERVICE_404 . COLON . $_which;
|
|
static::internalLog($msg);
|
|
return;
|
|
break;
|
|
}
|
|
|
|
// todo: SSL connectivity option
|
|
|
|
// build the connect string to the mongo resource based on the requesting environment
|
|
try {
|
|
$mongoData = static::buildMongoDSN($service);
|
|
if (is_null($mongoData) or !is_array($mongoData)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_DATA_METHOD_404, 'buildMongoDSN');
|
|
static::internalLog($msg);
|
|
return;
|
|
}
|
|
$mongoDSN = $mongoData[STRING_DSN];
|
|
$authSource = (empty($mongoData[STRING_AUTH_SRC])) ? CONFIG_ADMIN : $mongoData[STRING_AUTH_SRC];
|
|
$mongoOptions = $mongoData[STRING_OPTIONS];
|
|
} catch (TypeError $t) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_TYPE_EXCEPTION;
|
|
static::internalLog($msg);
|
|
static::internalLog($t->getMessage());
|
|
return;
|
|
}
|
|
|
|
try {
|
|
/*
|
|
* connect to the named mongo resource - note that mongo manager will always return a resource - even if
|
|
* there is no database to connect to - so, once we connect, issue a simple ping query to the named db to
|
|
* validate the connection.
|
|
*/
|
|
$res = new MongoDB\Driver\Manager($mongoDSN, $mongoOptions);
|
|
if (!is_object($res)) {
|
|
consoleLog($res, CON_SYSTEM, ERROR_MONGO_CONNECT . COLON . $_which);
|
|
return;
|
|
}
|
|
$command = new MongoDB\Driver\Command(['ping' => 1]);
|
|
@$res->executeCommand($authSource, $command); // was "admin" for $authsource; ok to ping the target db
|
|
// @$res->executeCommand('admin', $command);
|
|
switch ($_which) {
|
|
case MONGO_MASTER :
|
|
static::$resMongoMaster = $res;
|
|
static::$mongoMasterAvailable = true;
|
|
break;
|
|
case MONGO_ADMIN_MASTER :
|
|
static::$resMongoAdminMaster = $res;
|
|
static::$mongoAdminMasterAvailable = true;
|
|
break;
|
|
case MONGO_SEGUNDO_MASTER :
|
|
static::$resMongoSegundoMaster = $res;
|
|
static::$mongoSegundoMasterAvailable = true;
|
|
break;
|
|
case MONGO_WH_MASTER :
|
|
static::$resMongoWHMaster = $res;
|
|
static::$mongoWHMasterAvailable = true;
|
|
break;
|
|
case MONGO_TERCERO_MASTER :
|
|
static::$resMongoTerceroMaster = $res;
|
|
static::$mongoTerceroMasterAvailable = true;
|
|
break;
|
|
}
|
|
} catch (MongoDB\Driver\Exception\ConnectionException |
|
|
MongoDB\Driver\Exception\InvalidArgumentException |
|
|
MongoDB\Driver\Exception\RuntimeException |
|
|
MongoDB\Driver\Exception\Exception |
|
|
Throwable $e) { // superclass for sslConnection and TimeoutException
|
|
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
|
@handleExceptionMessaging($hdr, $e->getMessage(), $errors, true);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* buildMongoDSN() -- private static method
|
|
*
|
|
* This method requires one input parameter: the name of the current environment requesting a resource. This
|
|
* is a well-defined (e.g.: constant) value and pre-validated by the invoking client.
|
|
*
|
|
* The method builds an associative array which is returned to the calling client and is divided into three
|
|
* elements:
|
|
*
|
|
* 1. The mongo DSN (connect string) under the key: STRING_DSN
|
|
* 2. The mongo Authentication Source DB under the key: STRING_AUTH_SRC
|
|
* 3. The mongo options array (which is, itself, another associative array)
|
|
*
|
|
* Depending on which environment we're attempting to connect to, (defined in $_which), we'll pull that XML config
|
|
* block out from the mongo-config super-block and use that configuration data to build the mongo data necessary
|
|
* to connect to the named mongo resource.
|
|
*
|
|
* Any errors raised in processing will cause an error message to be generated and a null value returned to the
|
|
* calling client.
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @param string $_which
|
|
* @return array|null
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 07-23-18 mks CORE-1097: original coding
|
|
*
|
|
*/
|
|
private static function buildMongoDSN(string $_which): ?array
|
|
{
|
|
$validReadPrefs = [
|
|
'primary',
|
|
'primaryPreferred',
|
|
'secondary',
|
|
'secondaryPreferred',
|
|
'nearest'
|
|
];
|
|
$skipRPConfig = false;
|
|
$mongoDSN = MONGO_DSN;
|
|
// return array
|
|
$ra = [
|
|
STRING_DSN => null,
|
|
STRING_AUTH_SRC => null,
|
|
STRING_OPTIONS => null
|
|
];
|
|
// default read-preference
|
|
$mongoOptions[CONFIG_DATABASE_MONGODB_RP] = MONGODB\Driver\ReadPreference::RP_PRIMARY;
|
|
|
|
// note: user passwords, by default, are located in the target namaste db and not in the admin db
|
|
|
|
|
|
// build the DSN based on the correct env (appServer, segundo, tercero or admin) configuration sub-block
|
|
$thisConfig = static::$cfgMongo[$_which];
|
|
|
|
// step 1 -- ensure that the service ($_which) is local and active...
|
|
// if (intval(gasConfig::$settings[$_which][CONFIG_IS_LOCAL]) !== 1) {
|
|
// static::internalLog(sprintf(ERROR_SERVICE_NOT_LOCAL, $_which));
|
|
// return null;
|
|
// } elseif (intval(gasConfig::$settings[$_which][CONFIG_ACTIVE]) !== 1) {
|
|
// $msg = sprintf(ERROR_SERVICE_NOT_ACTIVE, $_which);
|
|
// static::internalLog($msg);
|
|
// return null;
|
|
// }
|
|
if (intval(gasConfig::$settings[$_which][CONFIG_ACTIVE]) !== 1) {
|
|
$msg = sprintf(ERROR_SERVICE_NOT_ACTIVE, $_which);
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
// the above commented-out block replaces the above code
|
|
|
|
// step 1a -- ensure that mongo is enabled on the current service
|
|
if (intval($thisConfig[CONFIG_DATABASE_MONGODB_ENABLED]) !== 1) {
|
|
// and that mongo is enabled for the service
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_LOCAL_SERVICE_404;
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
|
|
// Step 2 -- if RBAC enabled, grab the user credentials and inject into mongo-DSN
|
|
if (intval($thisConfig[CONFIG_DATABASE_MONGODB_USE_AUTH]) === 1) {
|
|
$mongoDSN .= $thisConfig[CONFIG_DATABASE_MONGODB_USER]. COLON_NS;
|
|
$mongoDSN .= $thisConfig[CONFIG_DATABASE_MONGODB_PASSWORD] . AT;
|
|
$authSource = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $thisConfig[CONFIG_DATABASE_MONGODB_AUTH_SOURCE];
|
|
$mongoOptions[CONFIG_DATABASE_MONGODB_AUTH_SOURCE] = $authSource;
|
|
$ra[STRING_AUTH_SRC] = $authSource;
|
|
}
|
|
|
|
// Step 3 -- evaluate the level of service in order of: sharded-cluster, replication-set, stand-alone-instance
|
|
if (intval($thisConfig[CONFIG_DATABASE_MONGODB_SHARDING][CONFIG_DATABASE_MONGODB_ENABLED]) === 1) {
|
|
// sharded cluster configuration
|
|
foreach($thisConfig[CONFIG_DATABASE_MONGODB_SHARDING][CONFIG_DATABASE_MONGODB_SHARDING_MONGOS_NODES] as $node) {
|
|
$mongoDSN .= $node . COMMA_NS;
|
|
}
|
|
$mongoDSN = rtrim($mongoDSN, COMMA_NS);
|
|
} elseif (intval($thisConfig[CONFIG_DATABASE_MONGODB_REPLSET][CONFIG_DATABASE_MONGODB_REPLSET_ENABLED]) === 1) {
|
|
// replication set configuration
|
|
$mongoOptions[MONGO_REPL_SET] = $thisConfig[CONFIG_DATABASE_MONGODB_REPLSET][CONFIG_DATABASE_MONGODB_REPLSET_NAME];
|
|
foreach ($thisConfig[CONFIG_DATABASE_MONGODB_REPLSET][CONFIG_DATABASE_MONGODB_REPLSET_DSN][CONFIG_DATABASE_MONGODB_ADMIN_REPLSET_SET] as $node) {
|
|
$mongoDSN .= $node . COMMA_NS;
|
|
}
|
|
$mongoDSN = rtrim($mongoDSN, COMMA_NS);
|
|
} else {
|
|
// stand-alone instance
|
|
$mongoDSN .= $thisConfig[CONFIG_DATABASE_MONGODB_HOST] . COLON_NS . $thisConfig[CONFIG_DATABASE_MONGODB_PORT];
|
|
$skipRPConfig = true;
|
|
}
|
|
if (isset(static::$logger) and static::$logger->available and gasConfig::$settings[CONFIG_DEBUG]) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . 'MongoDSN (' . static::$location . '): ' . $mongoDSN;
|
|
static::internalLog($msg);
|
|
}
|
|
$ra[STRING_DSN] = $mongoDSN;
|
|
|
|
// Step 4: add options: heartbeat and read-preferences to the options array
|
|
// heartbeat:
|
|
$mongoOptions[CONFIG_DATABASE_MONGODB_HB] = intval($thisConfig[CONFIG_DATABASE_MONGODB_HB]);
|
|
// readPreference: if the current env supports the read-secondary, then set the read-preference to the value
|
|
// stored as secondaryReadPreference, otherwise use readPreference (primary)
|
|
$mongoOptions[CONFIG_DATABASE_MONGODB_RP] = (isset($thisConfig[CONFIG_DATABASE_PDO_USE_SECONDARY]) === 1)
|
|
? $thisConfig[CONFIG_DATABASE_MONGODB_USE_READ_SECONDARY]
|
|
: $thisConfig[CONFIG_DATABASE_MONGODB_RP];
|
|
|
|
// if not a single-node-instance of mongo, get the readPreference from XML config and override the default
|
|
if (!$skipRPConfig) {
|
|
// $slaveReadPreference = $thisConfig[CONFIG_DATABASE_MONGODB_SECONDARY_RP];
|
|
if (!in_array($thisConfig[CONFIG_DATABASE_MONGODB_RP], $validReadPrefs)) {
|
|
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . sprintf(ERROR_MDB_INVALID_RP, $thisConfig[CONFIG_DATABASE_MONGODB_RP]);
|
|
static::internalLog($msg);
|
|
return null;
|
|
}
|
|
}
|
|
$ra[STRING_OPTIONS] = $mongoOptions;
|
|
return $ra;
|
|
}
|
|
|
|
|
|
/**
|
|
* internalLog() -- static private method
|
|
*
|
|
* This method requires a single input parameter - a string value which is the message to be logged.
|
|
*
|
|
* The method evaluates if the framework's logger resource is currently available and, if it is, publishes the
|
|
* message to the log file -- otherwise, the message is published to the namaste console.
|
|
*
|
|
* The method returns void.
|
|
*
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @param string $_msg
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 07-27-18 mks CORE-1108: initial coding
|
|
* 08-22-18 mks DB-49: consoleLog is default log vector -- add to mongodb log iff available
|
|
* 08-28-18 mks DB-49: squelching consoleLog output if client is a webApp, expanded exception trap
|
|
* 10-11-20 mks DB-168: ensuring logging is not engaged until after broker clients have started
|
|
*
|
|
*/
|
|
private static function internalLog(string $_msg): void
|
|
{
|
|
try {
|
|
if (gasResourceManager::$adminAvailable and isset(static::$logger) and isset(static::$logger->available) and static::$logger->available === true) {
|
|
static::$logger->info($_msg);
|
|
}
|
|
if (!(isset($_SERVER['HTTP_USER_AGENT']))) consoleLog(static::$myID, CON_SYSTEM, $_msg);
|
|
} catch (TypeError | Throwable $t) {
|
|
consoleLog(static::$myID, CON_ERROR, basename(__METHOD__) . AT . __LINE__ . COLON . $t->getMessage());
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* singleton() -- public static class
|
|
*
|
|
* method to instantiate the resourceManager singleton class
|
|
*
|
|
* note:
|
|
* -----
|
|
* it's the calling client's responsibility to check for the null return value in the member variable $instance.
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @return null
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding
|
|
*
|
|
*/
|
|
public static function singleton()
|
|
{
|
|
if (static::$instance === null) {
|
|
$c = __CLASS__;
|
|
static::$instance = new $c();
|
|
}
|
|
return(static::$instance);
|
|
}
|
|
|
|
|
|
/**
|
|
* __destruct() -- public method
|
|
*
|
|
* explicitly close any open resources - note that this is the only place in the framework where a resource
|
|
* connection is explicitly closed.
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding
|
|
*
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
|
//
|
|
// destructor is registered shut-down function in constructor -- so any recovery
|
|
// efforts should go in this method.
|
|
}
|
|
|
|
|
|
/**
|
|
* __clone() -- public function
|
|
*
|
|
* Silently disallows cloning of the object
|
|
*
|
|
* @author mike@givingassistant.org
|
|
* @version 1.0
|
|
*
|
|
* @return null
|
|
*
|
|
* HISTORY:
|
|
* ========
|
|
* 06-12-17 mks original coding
|
|
*
|
|
*/
|
|
private function __clone()
|
|
{
|
|
return null;
|
|
}
|
|
} |