null, //any
'maxCurrentVersion' => '5.1.19', //cannot be null. this is the latest version from the market
//interval for available versions
'minAvailableVersion' => '5.1.20', //cannot be null. this will be the version for unified
'maxAvailableVersion' => null, //any
'multiplier' => 2.5
);
/**
* ON-Premise OS upgrade requirements
*
* @var type
*/
protected $_osUpgradeRequirements = array(
// interval for current versions
'minCurrentVersion' => '5.1.20', // first unified version
'maxCurrentVersion' => '6.1.99', // last (possible) 12.04 version
// interval for available versions
'minAvailableVersion' => '6.2', // first 16.04 version
'maxAvailableVersion' => null, // any
'minDiskFreeSpace' => 5242880, // 5GB
'osVersion' => '12.04',
'dbRsConfigFile' => '/opt/bitdefender/etc/db.rs.json',
'productIds' => array(
1200, // DownloadableKits/repo_hydra_osupgrade_tools
1201, // DownloadableKits/repo_hydra_osupgrade
1202, // DownloadableKits/repo_hydra_ng_gz
),
'lastPingedAtTimeout' => 120,// 2 minutes
);
/**
* Conditions for checking if https access is blocked
*
* @var array
*/
private $httpsAccessibleRequirements = array(
// interval for current versions
'minCurrentVersion' => '6.2', // OS upgrade, last repo change
'maxCurrentVersion' => null, // any
'minAvailableVersion' => '6.5.5', // version with http -> https switch
'maxAvailableVersion' => null, // any
);
/**
* Conditions for allowing update to the new update system
*
* @var array
*/
private $updateSystemRequirements = array(
'minCurrentVersion' => '6.2', // OS upgrade, last repo change
'maxCurrentVersion' => '6.5.5', // latest release before update system refactoring
'minAvailableVersion' => '6.5.7', // version with the new update system
'allowDistributedDeployments' => true, // whenever distributed deployments or just AIO should be allowed
'maximumNumberOfEndpoints' => null, // maximum number of endpoints
'allowOfflineDeployments' => true // whenever we should allow the update on offline deployments
);
/**
* Constructor
*/
public function __construct() {
$this->_dal = Application::getInstance();
// load local dictionaries
$this->_loadInlineDictionaries();
$this->_typeConsole = defined('\Lib\Update\ApplianceInstallsHelper::TYPE_CONSOLE') ? ApplianceInstallsHelper::TYPE_CONSOLE : 0;
$this->_typeReportsBuilder = defined('\Lib\Update\ApplianceInstallsHelper::TYPE_REPORTS_BUILDER') ? ApplianceInstallsHelper::TYPE_REPORTS_BUILDER : 1;
}
/**
* Returns error messages for error constants
*
* @param integer $errorCode
* @param array $replacements
* @return string
*/
protected function _getTranslatedErrorMessage($errorCode, $replacements = array()) {
$errorMessage = '';
switch ($errorCode) {
case self::REQUIREMENTS_DISK_SPACE_ERROR:
$errorMessage = __('You do not have enough free disk space for this update. For further instructions, contact Bitdefender Enterprise Support.');
break;
case self::REQUIREMENTS_MISSING_DISK_SPACE_INFO_ERROR:
$errorMessage = __('Update cannot be performed. For further instructions, contact Bitdefender Enterprise Support.');
break;
case self::OS_UPGRADE_NOT_ENOUGH_FREE_SPACE:
$errorMessage = __('Not enough free disk space on these appliances to update: :IPS. For further instructions, contact Bitdefender Enterprise Support.', $replacements);
break;
case self::OS_UPGRADE_MISSING_DISK_SPACE_INFO:
$errorMessage = __('Update cannot be performed. For further instructions, contact Bitdefender Enterprise Support.');
break;
case self::OS_UPGRADE_INCOMPATIBLE_OS_VERSION:
$errorMessage = __('The OS version of these appliances is no longer supported: :IPS. For further instructions, contact Bitdefender Enterprise Support.', $replacements);
break;
case self::OS_UPGRADE_MISSING_OS_VERSION:
$errorMessage = __('Update cannot be performed. For further instructions, contact Bitdefender Enterprise Support.');
break;
case self::OS_UPGRADE_APPLIANCE_OFFLINE:
$errorMessage = __('The following appliances cannot be reached: :IPS. Make sure that the appliances are running and that they have network connectivity, and then try again.', $replacements);
break;
case self::OS_UPGRADE_BAD_RS_CONFIG:
$errorMessage = __('Incompatible deployment state (replica set configuration). For further instructions, contact Bitdefender Enterprise Support.');
break;
case self::OS_UPGRADE_REPOS_NOT_MIRRORED:
$errorMessage = __('Your update is being prepared. Please check again later. If this situation persists, check the network connection.');
break;
case self::OS_UPGRADE_UPDATE_SERVER_UNREACHABLE:
$errorMessage = __('Update cannot be performed. For further instructions, contact Bitdefender Enterprise Support.');
break;
case self::OS_UPGRADE_MISSING_UPDATE_SERVER_REPO_INFO:
// IPS are available in $replacements
$errorMessage = __('Update cannot be performed. For further instructions, contact Bitdefender Enterprise Support.');
break;
case self::OS_UPGRADE_UNOFFICIAL_REPO:
$errorMessage = __('The repositories file (/etc/apt/sources.list) is altered on these appliances: :IPS. The file must contain only the official Bitdefender repository!
1. Back up /etc/apt/sources.list.
2. Delete all repositories except the Bitdefender one. You can restore the repositories after the OS upgrade is complete.', $replacements);
break;
case self::REQUIREMENTS_HTTPS_BLOCKED:
$errorMessage = __("GravityZone has detected that the outbound port 443 is closed. You need to open this port on the corporate firewall to receive updates from Bitdefender Update Servers in the future. Details in release notes and in this KB article", array(
'RELEASE_NOTES_URL' => 'https://www.bitdefender.com/support/Bitdefender-GravityZone-6-5-5-1-Release-Notes-2374.html',
'KB_URL' => 'https://www.bitdefender.com/support/gravityzone-communication-ports-1132.html'
));
break;
case self::REQUIREMENTS_NEW_UPDATE_SYSTEM:
$errorMessage = __("GravityZone is revamping its update system. Your update will be ready to install in the near future. Read more", array(
'READ_MORE_URL' => $this->getDelayedUpdateLink()
));
break;
case self::REQUIREMENTS_SSH_CONNECT_FAILED:
$errorMessage = __('GravityZone cannot establish SSH communication on port 22. Open port 22 for GravityZone appliances, make sure that sshd listens on this port and that SSH has default configuration.');
break;
case self::REQUIREMENTS_OFFLINE_ENV_UPDATE_SYSTEM_REPOS_NOT_FOUND:
$errorMessage = __('The archive imported from the online GravityZone instance is outdated. Create a new archive on the online GravityZone instance. If the issue persists, deploy a new online GravityZone instance using the latest GravityZone image.');
break;
default:
$errorMessage = __('Update cannot be performed. For further instructions, contact Bitdefender Enterprise Support.');
break;
}
return $errorMessage;
}
/*
*
* Requirements checks - START
*
* Requirements checking methods should return errors as an array with error constants as keys and true or an array of replacements to be used in the translations as values
*
* Ex:
* return array(
*
* // this is translated like a call to __() with following parameter: 'Error message for constant self::ERROR_WITHOUT_PARAMS'
* self::ERROR_WITHOUT_PARAMS => true,
*
* // this is translated like a call to __() with following parameters: 'Error message for constant self::ERROR_WITH_PARAMS that contains this parameters :PARAM1 and :PARAM2', array('PARAM1' => 'param1', 'PARAM2' => 'param2')
* self::ERROR_WITH_PARAMS => array('PARAM1' => 'param1', 'PARAM2' => 'param2')
* );
*
*/
/**
* @param string $currentVersion
* @param string $availableVersion
* @return array
*/
private function _checkFreeDatabaseSpace($currentVersion, $availableVersion) {
if ($this->_shouldApplyRequirements($currentVersion, $availableVersion, $this->_freeDiskSpaceRequirements)) {
$dbAppliance = $this->_dal->ApplianceInstalls
->reset()
->selectFields('systemProperties', 'name')
->filter('name', '=', 'db')
->readSingle();
if (isset($dbAppliance['systemProperties']) && isset($dbAppliance['systemProperties']['databaseDiskSpace'])) {
$freeDiskSpace = $dbAppliance['systemProperties']['databaseDiskSpace']['available'];
$usedDiskSpace = $dbAppliance['systemProperties']['databaseDiskSpace']['used'];
if ($freeDiskSpace < $this->_freeDiskSpaceRequirements['multiplier'] * $usedDiskSpace) {
return array(self::REQUIREMENTS_DISK_SPACE_ERROR => true);
}
} else {
return array(self::REQUIREMENTS_MISSING_DISK_SPACE_INFO_ERROR => true);
}
} else {// for current and available versions out of range we shouldn't check this precondition
return array();
}
return array();
}
/**
* Checks if the OS can be updated from 12.04 to 16.04
*
* Performed checks:
* - free space
* - OS current version == 12.04
* - all appliances are online
* - correct (cli) replica set instalation
*
*
* @param type $currentVersion
* @param type $availableVersion
* @return type
*/
public function _checkOsUpgradeRequirements($currentVersion, $availableVersion) {
$errors = array();
if ($this->_shouldApplyRequirements($currentVersion, $availableVersion, $this->_osUpgradeRequirements)) {
$applianceInstallsHelper = new ApplianceInstallsHelper();
// read CONSOLE appliance data
$applianceRecords = $this->_dal->ApplianceInstalls
->reset()
->selectFields('applianceId', 'name', 'ip', 'systemProperties', 'lastPingedAt')
->filter('name', 'in', $applianceInstallsHelper->getConsoleRoles())// get only CONSOLE appliances
->read();
// keep one record for each appliance
$appliances = array();
$dbApplianceCount = 0;
foreach ($applianceRecords as $applianceRecord) {
if (!isset($appliances[$applianceRecord['applianceId']])) {
$appliances[$applianceRecord['applianceId']] = $applianceRecord;
}
if ($applianceRecord['name'] == 'db') {
$dbApplianceCount++;
}
}
foreach ($appliances as $appliance) {
/*
* Check free space on all CONSOLE appliances
*/
if (isset($appliance['systemProperties']['rootDiskSpace']['available'])) {
if ($appliance['systemProperties']['rootDiskSpace']['available'] < $this->_osUpgradeRequirements['minDiskFreeSpace']) {
$this->_addErrorAndPushText($errors, self::OS_UPGRADE_NOT_ENOUGH_FREE_SPACE, array('IPS' => $appliance['ip']));
}
} else {
$this->_addErrorAndPushText($errors, self::OS_UPGRADE_MISSING_DISK_SPACE_INFO, array('IPS' => $appliance['ip']));
}
/*
* check OS current version == 12.04
*/
if (isset($appliance['systemProperties']['osVersion'])) {
if ($appliance['systemProperties']['osVersion'] != $this->_osUpgradeRequirements['osVersion']) {
$this->_addErrorAndPushText($errors, self::OS_UPGRADE_INCOMPATIBLE_OS_VERSION, array('IPS' => $appliance['ip']));
}
} else {
$this->_addErrorAndPushText($errors, self::OS_UPGRADE_MISSING_OS_VERSION, array('IPS' => $appliance['ip']));
}
/*
* Check that this appliance is using only official GZ repos
*/
if (!isset($appliance['systemProperties']['officialRepo']) || !$appliance['systemProperties']['officialRepo']) {
$this->_addErrorAndPushText($errors, self::OS_UPGRADE_UNOFFICIAL_REPO, array('IPS' => $appliance['ip']));
}
}
/*
* check that all appliances are online
*/
if (count($appliances) > 1) {
$currentApplianceId = ApplianceUtils::getApplianceId();
$now = time();
foreach ($appliances as $appliance) {
// if not local appliance
if ($appliance['applianceId'] != $currentApplianceId) {
if (!isset($appliance['lastPingedAt']) || strtotime($appliance['lastPingedAt']) < $now - $this->_osUpgradeRequirements['lastPingedAtTimeout']) {
$this->_addErrorAndPushText($errors, self::OS_UPGRADE_APPLIANCE_OFFLINE, array('IPS' => $appliance['ip']));
}
}
}
}
/*
* check for correct (cli) replica set installation
*/
if (file_exists($this->_osUpgradeRequirements['dbRsConfigFile']) && $dbApplianceCount <= 1) {
$errors[self::OS_UPGRADE_BAD_RS_CONFIG] = true;
}
/*
* check that all repos are mirrored by Update Server
*/
try {
do {
// create KitOperations instance
$updateServer = new UpdateServerRequestHelper();
$params = array();
foreach ($this->_osUpgradeRequirements['productIds'] as $productId) {
$params[] = array('productId' => $productId, 'oemId' => null);
}
// get the latest version available for each repo
$results = $updateServer->getLatestVersionsUpdatesMulti($params);
Logger::debug('Requirements:', 'getLatestVersionsUpdates', $results);
$latestVersions = array();
foreach ($results as $result) {
if (
in_array($result['productId'], $this->_osUpgradeRequirements['productIds']) &&
isset($result[UpdateServerRequestHelper::RING_ID_SLOW])
) {
$latestVersions[$result['productId']] = $result[UpdateServerRequestHelper::RING_ID_SLOW];
}
}
if (count($latestVersions) != count($this->_osUpgradeRequirements['productIds'])) {
// some repos are missing from the response
$errors[self::OS_UPGRADE_REPOS_NOT_MIRRORED] = true;
break;
}
// get the status for each repo and check that the latest version is published
$results = $updateServer->getUpdateListStatusMulti($params);
Logger::debug('Requirements:', 'getUpdateListStatus', $results);
// for each productId's latest version
foreach ($latestVersions as $productId => $latestVersion) {
// find the kit list for the productId
foreach ($results as $result) {
if ($result['productId'] == $productId) {
// if the version list exists
if (isset($result['productVersions']) && is_array($result['productVersions'])) {
// search for the latest version
foreach ($result['productVersions'] as $versionData) {
if ($versionData['productVersion'] == $latestVersion) {
// check the latest version's statuse
if (
$versionData['status'] == UpdateServerRequestHelper::STATUS_DOWNLOADED &&
is_array($versionData['publishedOnRings']) &&
in_array(UpdateServerRequestHelper::RING_ID_SLOW, $versionData['publishedOnRings'])
) {
// process next latest version
continue 3;
}
// stop processing the versions of this result
break;
}
}
$errors[self::OS_UPGRADE_REPOS_NOT_MIRRORED] = true;
// process next appliance
break 2;
} else {
$errors[self::OS_UPGRADE_REPOS_NOT_MIRRORED] = true;
// process next appliance
break 2;
}
// process next latest version
break;
}
}
}
} while (false);
} catch (BDConsoleException $e) {
Logger::error('Error qeurying the Update Server', $e->getMessage(), $e->getTraceAsString());
$errors[self::OS_UPGRADE_UPDATE_SERVER_UNREACHABLE] = true;
}
}
return $errors;
}
/**
* Checks if GZ can access BD servers via HTTPS
*
* @param string $currentVersion Current GZ version
* @param string $availableVersion Available GZ version
*
* @return array List of errors if any
*/
private function checkHttpsAccess($currentVersion, $availableVersion) {
// check if this requirement should be checked
if (!$this->_shouldApplyRequirements($currentVersion, $availableVersion, $this->httpsAccessibleRequirements)) {
return array();
}
// we should not make the check for offline deployments
if ($this->isOfflineDeployment()) {
return array();
}
$urls = array(
"https://upgrade.bitdefender.com/",
"https://download.bitdefender.com/"
);
// get a cURL handle with any proxy settings set
$curl = HydraCurl::Instance()->getCurl();
// list of errors that could be caused by a blocked HTTPS port (connect or timeout errors)
$fatalErrors = array(
CURLE_COULDNT_CONNECT,
CURLE_OPERATION_TIMEDOUT,
CURLE_RECV_ERROR
);
// initialize result array
$result = array();
// check each connection, if any fails, HTTPS might be blocked, do not allow update
foreach ($urls as $url) {
curl_setopt($curl, CURLOPT_URL, $url);
// if curl_exec succeeded, we should be fine
if (curl_exec($curl) !== false) {
continue;
}
// ignore errors not in fatal list
if (!in_array(curl_errno($curl), $fatalErrors)) {
continue;
}
// connection troubles, set HTTPS Blocked error and stop checking, one error is too much
$result[self::REQUIREMENTS_HTTPS_BLOCKED] = true;
break;
}
// cleanup
curl_close($curl);
return $result;
}
/**
* Checks if GZ update containing the new update system is available for current deployment
*
* @param string $currentVersion Current GZ version
* @param string $availableVersion Available GZ version
*
* @return array List of errors if any
*/
private function checkUpdateSystemRequirements($currentVersion, $availableVersion) {
// check if this requirement should be checked
if (!$this->_shouldApplyRequirements($currentVersion, $availableVersion, $this->updateSystemRequirements)) {
return array();
}
$result = array();
// is offline deployment condition met?
if (!$this->updateSystemRequirements['allowOfflineDeployments']) {
if ($this->isOfflineDeployment()) {
$result[self::REQUIREMENTS_NEW_UPDATE_SYSTEM] = true;
}
}
// is deployment type condition met?
if (!count($result) && !$this->updateSystemRequirements['allowDistributedDeployments']) {
// get number of VAs installed, AIO should have exactly 1
// if more than one since condition is not met, the update unavailable message should be returned
$applianceIds = $this->_dal->ApplianceInstalls->reset()->getDistinctValues("applianceId");
if (count($applianceIds) > 1) {
$result[self::REQUIREMENTS_NEW_UPDATE_SYSTEM] = true;
}
}
// if we did not already failed a condition and number of endpoints should
// be checked, do that
if (!count($result) && isset($this->updateSystemRequirements['maximumNumberOfEndpoints'])) {
// get number of endpoints and check against the requirement
// set update not available message if number larger than one in condition
$endpointsCount = $this->_dal->Endpoints->reset()->count();
if ($endpointsCount > $this->updateSystemRequirements['maximumNumberOfEndpoints']) {
$result[self::REQUIREMENTS_NEW_UPDATE_SYSTEM] = true;
}
}
// check ssh connecivity
if (!count($result) && !$this->checkSshConnectivity()) {
$result[self::REQUIREMENTS_SSH_CONNECT_FAILED] = true;
}
// for offline deployments, check that new repos are accesible with http
if (!count($result) && $this->isOfflineDeployment() && !$this->checkHttpUpdateSystemRepos()) {
$result[self::REQUIREMENTS_OFFLINE_ENV_UPDATE_SYSTEM_REPOS_NOT_FOUND] = true;
}
return $result;
}
/**
* Checks that the Update System repos are accesible with http.
*/
private function checkHttpUpdateSystemRepos() {
$repoUrls = [
'http://download.bitdefender.com/repos/deb-hydra16-intermediary',
'http://download.bitdefender.com/repos/deb-hydra16-unified'
];
foreach ($repoUrls as $urlToCheck) {
// get curl instance
$curl = HydraCurl::Instance()->getCurl();
// set curl options
curl_setopt($curl, CURLOPT_URL, $urlToCheck);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 0);
// do request
$body = curl_exec($curl);
if ($body === false || curl_getinfo($curl, CURLINFO_RESPONSE_CODE) !== 200) {
// cleanup
curl_close($curl);
// repo url is not accesible
return false;
}
// cleanup
curl_close($curl);
}
// all repo urls were accesible
return true;
}
/**
* Checks that all appliances are reachable using ssh
*/
private function checkSshConnectivity() {
// get all appliances
$applianceRecords = $this->_dal->ApplianceInstalls
->reset()
->selectFields('applianceId')
->read();
// try to ssh
foreach ($applianceRecords as $applianceRecord) {
if (!isset($applianceRecord['applianceId'])) {
return false;
}
try {
$connection = ssh2_connect($applianceRecord['applianceId'], 22);
if ($connection === false) {
return false;
}
$authMethods = ssh2_auth_none($connection, 'user');
if (function_exists('ssh2_disconnect')) {
ssh2_disconnect($connection);
}
if (!is_array($authMethods) || !in_array('publickey', $authMethods)) {
return false;
}
} catch (\Exception $e) {
return false;
}
}
// succesfully connected to all appliances
return true;
}
/**
* Checks if current deployment runs in off-line mode
*
* @return bool Returns TRUE if current deployment runs in off-line mode
*/
private function isOfflineDeployment() {
$isOffline = false;
// in off-line mode, the requests to http://download.bitdefender.com are
// redirected to local Arrakis server, port 7074
// Unlinke the Bitdefender server, the local Arrakis server does not
// set "Server:" header. We can use this to detect if current
// install runs in off-line mode.
// url to check
$urlToCheck = "http://download.bitdefender.com/";
// get a cURL handle with any proxy settings set
$curl = HydraCurl::Instance()->getCurl();
// set cURL options, do not return content, only headers
curl_setopt($curl, CURLOPT_URL, $urlToCheck);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_NOBODY, 1);
// if curl_exec succeeded, check for header existence
$headers = curl_exec($curl);
if ($headers !== false) {
// no Server: header found, means we are offline
$isOffline = !preg_match('/^server: [^S]/im', $headers);
}
// cleanup
curl_close($curl);
return $isOffline;
}
/**
* Get user localization if authenticated or default if not
*
* @throws \DAL\Exceptions\ParameterException
* @return string User localization
*/
private function getUserLanguage() {
/**
* @var \DAL\Modules\I18N\Main $i18n
*/
$i18n = $this->_dal->getModulesManager()->getModuleInstance('I18N');
// get list of languages and default language from I18N module
$language = $i18n->getDefaultLanguage();
$allLanguages = $i18n::$langMapping;
// COOKIE set language has priority, is lang cookie set and valid?
if (isset($_COOKIE['lang']) && array_key_exists($_COOKIE['lang'], $allLanguages)) {
// get language from cookie
$language = $_COOKIE['lang'];
} else {
// get current user, if success, get language from profile
$user = $this->_dal->getSecurityManager()->getUser();
if ($user && isset($user['profile']['language'])) {
$language = $user['profile']['language'];
}
}
return $language;
}
/**
* Gets link to be displayed in the "delayed update" message, based on current user's locale
*
* @throws \DAL\Exceptions\ParameterException
*
* @return string Link to "Read more" for update system delay
*/
private function getDelayedUpdateLink() {
// list of links by language and the default link for untranslated page
$links = array(
'en_US' => 'https://www.bitdefender.com/support/faq-about-gravityzone-update-to-version-6-6-1-2-2396.html',
'es_ES' => 'https://www.bitdefender.es/support/faq-about-gravityzone-update-to-version-6-6-1-2-2396.html',
'de_DE' => 'https://www.bitdefender.de/support/faq-about-gravityzone-update-to-version-6-6-1-2-2396.html',
'fr_FR' => 'https://www.bitdefender.fr/support/faq-about-gravityzone-update-to-version-6-6-1-2-2396.html',
'ro_RO' => 'https://www.bitdefender.ro/support/faq-about-gravityzone-update-to-version-6-6-1-2-2396.html',
'it_IT' => 'https://www.bitdefender.it/support/faq-about-gravityzone-update-to-version-6-6-1-2-2396.html'
);
$defaultLink = $links['en_US'];
// get language for current user
$language = $this->getUserLanguage();
// set link based on language if set, default otherwise
$link = $defaultLink;
if (isset($links[$language])) {
$link = $links[$language];
}
return $link;
}
/*
*
* Requirements checks - END
*
*/
/**
* @param string | null $currentVersion
* @param string | null $availableVersion
* @param array $requirementsParams Named parameter
* @return array An array with specific error messages for each update requirement
*/
public function checkRequirements($currentVersion, $availableVersion, $requirementsParams = null) {
// array of outdated appliances
$outdatedAppliances = array();
// checks for backward compatibility
if ($currentVersion != null || $availableVersion != null) {
$outdatedAppliances[$this->_typeConsole] = array(
'currentVersion' => $currentVersion,
'availableVersion' => $availableVersion
);
} else if (isset($requirementsParams['outdatedAppliances'])) {
$outdatedAppliances = $requirementsParams['outdatedAppliances'];
}
$requirementsErrors = array();
foreach ($outdatedAppliances as $productType => $applianceVersions) {
switch ($productType) {
case $this->_typeConsole:
//this is the first requirement
$requirementsErrors = array_replace($requirementsErrors, $this->_checkFreeDatabaseSpace($applianceVersions['currentVersion'], $applianceVersions['availableVersion']));
// check requirements for OS update
$requirementsErrors = array_replace($requirementsErrors, $this->_checkOsUpgradeRequirements($applianceVersions['currentVersion'], $applianceVersions['availableVersion']));
// check requirements for HTTPS access
$requirementsErrors = array_replace($requirementsErrors, $this->checkHttpsAccess($applianceVersions['currentVersion'], $applianceVersions['availableVersion']));
// check requirements for new update system
$requirementsErrors = array_replace($requirementsErrors, $this->checkUpdateSystemRequirements($applianceVersions['currentVersion'], $applianceVersions['availableVersion']));
break;
case $this->_typeReportsBuilder:
// todo implement requirements for Reports Builder update
break;
}
}
if (count($requirementsErrors) == 0) {
$this->_dal->Settings->readAndModify(array(
'updateRequirementsPassed' => true
));
} else {
$this->_dal->Settings->readAndModify(array(
'updateRequirementsPassed' => false
));
Logger::error('Requirements:', 'Failed requirements:', $requirementsErrors);
}
$errors = array();
if (isset($requirementsParams['returnTranslatesStrings']) && $requirementsParams['returnTranslatesStrings']) {
// convert the values of the error constants to error messages
foreach ($requirementsErrors as $errorConstant => $replacements) {
$errors[] = $this->_getTranslatedErrorMessage($errorConstant, is_array($replacements) ? $replacements : array());
}
// some error constants have the same error message
$errors = array_values(array_unique($errors));
} else {
// return only the error constants
$errors = array_keys($requirementsErrors);
}
return $errors;
}
/*
*
* Suspend auto-update - START
*
*/
/**
* Checks if the auto-update should be suspended before the OS Upgrade
*
* @param string $currentVersion
* @param string $availableVersion
* @return boolean
*/
protected function _osUpdateSuspendAutoUpdate($currentVersion, $availableVersion) {
if ($this->_shouldApplyRequirements($currentVersion, $availableVersion, $this->_osUpgradeRequirements)) {
return true;
}
return false;
}
/*
*
* Suspend auto-update - END
*
*/
/**
* Returns true if the auto-update is suspended
*
* @param array $requirementsParams
* @return boolean
*/
public function isAutoUpdateSuspended($requirementsParams = null) {
// default value
$isAutoUpdateSuspended = false;
if (isset($requirementsParams['outdatedAppliances'])) {
$outdatedAppliances = $requirementsParams['outdatedAppliances'];
foreach ($outdatedAppliances as $productType => $applianceVersions) {
switch ($productType) {
case $this->_typeConsole:
// check if OS Upgrade suspends auto-update
$isAutoUpdateSuspended = $isAutoUpdateSuspended || $this->_osUpdateSuspendAutoUpdate($applianceVersions['currentVersion'], $applianceVersions['availableVersion']);
/*
* To add another check for suspending the auto update just add a line like:
*
* $isAutoUpdateSuspended = $isAutoUpdateSuspended || $this->_myMethodThatChecksIfTheAutoUpdateIsSuspended($applianceVersions['currentVersion'], $applianceVersions['availableVersion']);
*
* If any of the auto-update suspend tests return true than the return value of isAutoUpdateSuspended() is true.
*/
break;
case $this->_typeReportsBuilder:
// todo implement suspend auto-update for Reports Builder
break;
}
}
}
return $isAutoUpdateSuspended;
}
/*
*
* Warning messages - START
*
*/
/**
* Returns the OS Upgrade warning messages
*
* @param string $currentVersion
* @param string $availableVersion
* @return array
*/
protected function _getOsUpgradeWarningMessages($currentVersion, $availableVersion) {
if ($this->_shouldApplyRequirements($currentVersion, $availableVersion, $this->_osUpgradeRequirements)) {
$messages = array(
'warning' => __('The following update is upgrading the OS of the GravityZone appliances.
This process can last over 30 minutes.
Auto-update has been disabled for this update, as it requires your attention.
With this update, any customization of your appliances will be lost.
Before you begin it is very important to :
1. Take snapshots of your appliances.
2. Open port 9443 to accept both incoming and outgoing traffic from and to the other GravityZone appliances (if applicable).'),
'confirmation' => __('By continuing, you confirm you have taken snapshots of your appliances. Proceed with the upgrade?'),
);
return $messages;
}
return array();
}
/*
*
* Warning messages - END
*
*/
/**
* Gets update warning messages
*
* @param array $requirementsParams
* @return array
*/
public function getWarningMessages($requirementsParams = null) {
// default value
$warningMessages = array();
if (isset($requirementsParams['outdatedAppliances'])) {
$outdatedAppliances = $requirementsParams['outdatedAppliances'];
foreach ($outdatedAppliances as $productType => $applianceVersions) {
switch ($productType) {
case $this->_typeConsole:
// get the OS Upgrade warning messages
$messages = $this->_getOsUpgradeWarningMessages($applianceVersions['currentVersion'], $applianceVersions['availableVersion']);
if ($messages) {
$warningMessages = $messages;
}
/*
* To add another set of messages just add a code snippet like:
*
* $messages = $this->_myMethodThatReturnsWarningMessages($applianceVersions['currentVersion'], $applianceVersions['availableVersion']);
*
* if ($messages) {
* $warningMessages = $messages;
* }
*
* Older warning messages are overwritten by newer warning messages.
* Take note that reports builder messages overwite console messages.
*/
break;
case $this->_typeReportsBuilder:
// todo implement warning messages for Reports Builder
break;
}
}
}
return $warningMessages;
}
/**
* Adds locales contained in this file to the global dictionaries
*/
protected function _loadInlineDictionaries() {
if ($this->_dal->getSecurityManager()->isAuthenticated() || $this->_dal->getSecurityManager()->isServiceMode()) {
// get current user
$user = $this->_dal->getSecurityManager()->getUser();
// set user language
if (
isset($user['profile']['language']) &&
isset($this->_inlineDictionaries[$user['profile']['language']]) &&
is_array($this->_inlineDictionaries[$user['profile']['language']])
) {
$i18n = $this->_dal->getModulesManager()->getModuleInstance('I18N');
if (method_exists($i18n, 'mergeIntoCurrentDictionary')) {
$i18n->mergeIntoCurrentDictionary($this->_inlineDictionaries[$user['profile']['language']]);
} else {
Logger::warning('Requirements:', 'Local dictionaries not loaded. Error messages might not be translated.');
}
}
}
}
/**
* Checks if requirements should be applied given the current and available version
*
* @param string $currentVersion
* @param string $availableVersion
* @param array $constraintsArray
* @return boolean
*/
protected function _shouldApplyRequirements($currentVersion, $availableVersion, $constraintsArray) {
// trim build number
$currentVersion = explode("-", $currentVersion);
$currentVersion = $currentVersion[0];
// trim build number
$availableVersion = explode("-", $availableVersion);
$availableVersion = $availableVersion[0];
// check current version conditions
$isMinCurrentVersionConditionMet = !isset($constraintsArray['minCurrentVersion']) || version_compare($currentVersion, $constraintsArray['minCurrentVersion']) >= 0;
$isMaxCurrentVersionConditionMet = !isset($constraintsArray['maxCurrentVersion']) || version_compare($currentVersion, $constraintsArray['maxCurrentVersion']) <= 0;
$isCurrentVersionConditionMet = $isMaxCurrentVersionConditionMet && $isMinCurrentVersionConditionMet;
$isMinAvailableVersionConditionMet = !isset($constraintsArray['minAvailableVersion']) || version_compare($availableVersion, $constraintsArray['minAvailableVersion']) >= 0;
$isMaxAvailableVersionConditionMet = !isset($constraintsArray['maxAvailableVersion']) || version_compare($availableVersion, $constraintsArray['maxAvailableVersion']) <= 0;
$isAvailableVersionConditionMet = $isMinAvailableVersionConditionMet && $isMaxAvailableVersionConditionMet;
return $isCurrentVersionConditionMet && $isAvailableVersionConditionMet;
}
/**
* Adds new error codes to $errors as follows:
* - error constant values are used as keys
* - texts that need to be added to the translations are concatenated. The resulting arrays are used as values in the $errors array.
*
* @param array $errors Array of errors
* @param integer $errorCode Error constant value
* @param array $replacements Array representing replacements to be used in the translation of the error message
* @param type $glue String used to concatenate the values in the replacements
*/
protected function _addErrorAndPushText(&$errors, $errorCode, $replacements, $glue = ', ') {
if (isset($errors[$errorCode])) {
foreach ($replacements as $key => $value) {
if (isset($errors[$errorCode][$key])) {
$errors[$errorCode][$key] .= "{$glue}{$value}";
} else {
$errors[$errorCode][$key] = $value;
}
}
} else {
$errors[$errorCode] = $replacements;
}
}
/**
* Localizations for the error messages used in the update requirements
*
* This is placed here to allow for automatic building
*
* Format:
* $_inlineDictionaries = array(
* 'en_US' => array(
* 'You do not have enough free disk space for this update. Please contact Bitdefender Enterprise Support.' => 'You do not have enough free disk space for this update. Please contact Bitdefender Enterprise Support.',
* 'Update cannot be performed. Please contact Bitdefender Enterprise Support.' => 'Update cannot be performed. Please contact Bitdefender Enterprise Support.',
* )
* )
*
* The section between the markers is generated by the requirements builder: Tools/RequirementsBuilder/Builder.php
*
* Steps to rebuild the local dictionaries:
* 1. Add the error constants and error messages in the requirements file (this file)
* Error constants should be added to this class and the coresponding messages should be added to the _getTranslatedErrorMessage() method.
*
* 2. Translate and update dictionaries in version control
* When extracting the locales to be translated the locales found in this file will be added to the data-provider dictionary.
* After translating the extracted dictionaries and committing them to version control, translations for the locales found in this file will be found in the data-provider dictionary.
*
* 3. Run the requirements builder
* The requirements builder extracts locales from this file and searches for translations in the data-provider dictionaries (for all available languages).
* The builder then edits this file and replaces the local dictionaries between the commented tags: and
*
* @var array
*/
protected $_inlineDictionaries =
/**/
array(
'en_US' =>
array(
'You do not have enough free disk space for this update. Please contact Bitdefender Professional Services.' => 'You do not have enough free disk space for this update. Please contact Bitdefender Professional Services.',
'Update cannot be performed. Please contact Bitdefender Professional Services.' => 'Update cannot be performed. Please contact Bitdefender Professional Services.',
),
'es_ES' =>
array(
'You do not have enough free disk space for this update. Please contact Bitdefender Professional Services.' => 'No tiene suficiente espacio libre en disco para esta actualización.Por favor, póngase en contacto con los Servicios Profesionales de Bitdefender.',
'Update cannot be performed. Please contact Bitdefender Professional Services.' => 'No se puede realizar la actualización.Por favor, póngase en contacto con los Servicios Profesionales de Bitdefender.',
),
'de_DE' =>
array(
'You do not have enough free disk space for this update. Please contact Bitdefender Professional Services.' => 'Sie verfügen nicht genügend Speicherplatz für dieses Update. Bitte kontaktieren Sie Bitdefender Professional Services.',
'Update cannot be performed. Please contact Bitdefender Professional Services.' => 'Aktualisierung kann nicht ausgeführt werden. Bitte kontaktieren Sie Bitdefender Professional Services.',
),
'fr_FR' =>
array(
'You do not have enough free disk space for this update. Please contact Bitdefender Professional Services.' => 'Vous n’avez pas assez d’espace disque libre pour cette mise à jour. Merci de contacter le Support Bitdefender pour Entreprises.',
'Update cannot be performed. Please contact Bitdefender Professional Services.' => 'La mise à jour ne peut pas être effectuée. Merci de contacter le Support Bitdefender pour Entreprises.',
),
'ro_RO' =>
array(
'You do not have enough free disk space for this update. Please contact Bitdefender Professional Services.' => 'Nu aveți suficient spațiu pe disc disponibil pentru această actualizare. Vă rugăm să contactați departamentul Bitdefender Professional Services.',
'Update cannot be performed. Please contact Bitdefender Professional Services.' => 'Actualizarea nu poate fi efectuată. Vă rugăm să contactați departamentul Bitdefender Professional Services.',
),
'pl_PL' =>
array(
'You do not have enough free disk space for this update. Please contact Bitdefender Professional Services.' => 'Nie masz wystarczającej ilości wolnego miejsca na dysku dla tej aktualizacji. Skontaktuj się proszę z Bitdefender Professional Services.',
'Update cannot be performed. Please contact Bitdefender Professional Services.' => 'Aktualizacja nie może być wykonana. Skontaktuj się proszę z Bitdefender Professional Services.',
),
)/**/
;
}