host/AzureRecoveryLib/config/RecoveryConfig.cpp (359 lines of code) (raw):

/* +------------------------------------------------------------------------------------+ Copyright(c) Microsoft Corp. 2015 +------------------------------------------------------------------------------------+ File : RecoveryConfig.cpp Description : AzureRecoveryConfig class is implementation. History : 7-5-2015 (Venu Sivanadham) - Created +------------------------------------------------------------------------------------+ */ #include "RecoveryConfig.h" #include "../common/Trace.h" #include "../common/AzureRecoveryException.h" #include "../resthelper/HttpUtil.h" #include <boost/foreach.hpp> #include <boost/assert.hpp> #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> namespace AzureRecovery { // Singleton AzureRecoveryConfig object AzureRecoveryConfig AzureRecoveryConfig::s_config_obj; /* Method : AzureRecoveryConfig::AzureRecoveryConfig AzureRecoveryConfig::~AzureRecoveryConfig Description : AzureRecoveryConfig constructor & descrtuctor Parameters : None Return Code : None */ AzureRecoveryConfig::AzureRecoveryConfig() :m_bInitialized(false) { m_logLevel = LogLevelAlways; m_scsiHost = DEFAULT_SCSI_HOST_NUM; m_sysMountPoint = DEFAULT_SYS_MOUNT_POINT; m_bTestFailover = false; m_bEnableRDP = false; m_bIsUefi = false; m_activePartitionStartingOffset = 0; } AzureRecoveryConfig::~AzureRecoveryConfig() { } /* Method : AzureRecoveryConfig::SetDiskMap Description : Reads the DiskMap section from parsed recovery config tree structure and sets them to disks map data member. Parameters : [in] tree: parsed recovery config tree structure Return Code : None */ void AzureRecoveryConfig::SetDiskMap(const conf_tree& tree) { TRACE_FUNC_BEGIN; TRACE("Parsing [DiskMap] section:\n"); conf_tree disk_tree = tree.get_child(RecoveryConfigKey::DISK_MAP_SECTION); for (conf_tree::const_iterator iterDisk = disk_tree.begin(); iterDisk != disk_tree.end(); iterDisk++) { TRACE("%s = %s\n", iterDisk->first.c_str(), iterDisk->second.data().c_str()); m_disks[iterDisk->first] = boost::lexical_cast<int>(iterDisk->second.data()); } TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetStatusBlobUri Description : Reads the blob-sas key from parsed data and sets to the its data member. Parameters : [in] tree: parsed recovery config tree structure Return Code : None An exception will be thrown if blob-sas is empty. */ void AzureRecoveryConfig::SetStatusBlobUri(const conf_tree& tree) { TRACE_FUNC_BEGIN; m_blob_sas = tree.get<std::string>(RecoveryConfigKey::STATUS_BLOB_URI); if (m_blob_sas.empty()) THROW_CONFIG_EXCEPTION("Blob SAS should not be empty"); AzureStorageRest::Uri uri(m_blob_sas); TRACE("%s\n", uri.GetResourceUri().c_str()); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetSCSIHost Description : Reads the ScsiHost key from parsed data and sets to the its data member. Parameters : [in] tree: parsed recovery config tree structure Return Code : None An exception will be thrown if bad value present for ScsiHost key. */ void AzureRecoveryConfig::SetSCSIHost(const conf_tree& tree) { TRACE_FUNC_BEGIN; try { std::string strScsiHost = tree.get<std::string>(RecoveryConfigKey::SCSI_HOST); if (!strScsiHost.empty()) m_scsiHost = boost::lexical_cast<int>(strScsiHost); } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::SCSI_HOST, exp.what()); // // Its an optional key, not considering it as failure // } catch (boost::bad_lexical_cast& cast_exp) { TRACE_ERROR("Bad value in %s key\n", RecoveryConfigKey::SCSI_HOST); THROW_CONFIG_EXCEPTION("Bad ScsiHost value in recovery config file"); } TRACE("%d\n", m_scsiHost); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetLogLevel Description : Reads the LogLevel key from parsed data and sets to the its data member. Parameters : [in] tree: parsed recovery config tree structure Return Code : None An exception will be thrown if bad value present for Loglevel key. */ void AzureRecoveryConfig::SetLogLevel(const conf_tree& tree) { TRACE_FUNC_BEGIN; try { std::string strLoglevel = tree.get<std::string>(RecoveryConfigKey::LOG_LEVEL); if (!strLoglevel.empty()) { int iLogLevel = boost::lexical_cast<int>(strLoglevel); m_logLevel = (LogLevel)(iLogLevel > LogLevelTrace ? LogLevelTrace : iLogLevel); } } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::LOG_LEVEL, exp.what()); // // Its an optional key, not considering it as failure // } catch (boost::bad_lexical_cast& cast_exp) { TRACE_ERROR("Bad value in %s key\n", RecoveryConfigKey::LOG_LEVEL); THROW_CONFIG_EXCEPTION("Bad LogLevel value in recovery config file"); } TRACE("%d\n", m_logLevel); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetBootDevice Description : Opens the recovery config file and parses its content. Parameters : [in] tree: parsed recovery config tree structure Return Code : None */ void AzureRecoveryConfig::SetSysMountPoint(const conf_tree& tree) { TRACE_FUNC_BEGIN; try { m_sysMountPoint = tree.get<std::string>(RecoveryConfigKey::SYS_MOUNT_POINT); } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::SYS_MOUNT_POINT, exp.what() ); // // Its an optional key, not considering it as failure // } TRACE("%s\n", m_sysMountPoint.c_str()); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetNewHostId Description : Opens the recovery config file and parses its content. Parameters : [in] tree: parsed recovery config tree structure Return Code : None */ void AzureRecoveryConfig::SetNewHostId(const conf_tree& tree) { TRACE_FUNC_BEGIN; m_newHostId = tree.get<std::string>(RecoveryConfigKey::NEW_HOST_ID); if (m_newHostId.empty()) THROW_CONFIG_EXCEPTION("HostId value should not be empty in recovery config file"); TRACE("%s\n", m_newHostId.c_str()); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetTestFailover Description : Opens the recovery config file and parses its content. Parameters : [in] tree: parsed recovery config tree structure Return Code : None */ void AzureRecoveryConfig::SetTestFailover(const conf_tree& tree) { TRACE_FUNC_BEGIN; try { std::string testFailoverKeyVal = tree.get<std::string>(RecoveryConfigKey::TEST_FAILOVER); m_bTestFailover = boost::iequals(testFailoverKeyVal, "true"); } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::TEST_FAILOVER, exp.what()); // // Its an optional key, not considering it as failure // } TRACE("%s\n", m_bTestFailover ? "test failover" : "failover"); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetEnableRDP Description : Opens the recovery config file and parses its content. Parameters : [in] tree: parsed recovery config tree structure Return Code : None */ void AzureRecoveryConfig::SetEnableRDP(const conf_tree& tree) { TRACE_FUNC_BEGIN; try { std::string enableRDPKeyVal = tree.get<std::string>(RecoveryConfigKey::ENABLE_RDP); m_bEnableRDP = boost::iequals(enableRDPKeyVal, "true"); } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::ENABLE_RDP, exp.what()); // // Its an optional key, not considering it as failure // } TRACE("EnableRDP : %s\n", m_bEnableRDP ? "true" : "false"); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetIsUEFI Description : Opens the recovery config file and parses its content. Parameters : [in] tree: parsed recovery config tree structure Return Code : None */ void AzureRecoveryConfig::SetIsUEFI(const conf_tree& tree) { TRACE_FUNC_BEGIN; try { std::string isUefiKeyVal = tree.get<std::string>(RecoveryConfigKey::IS_UEFI); m_bIsUefi = boost::iequals(isUefiKeyVal, "true"); } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::ENABLE_RDP, exp.what()); // // Its an optional key, not considering it as failure // } TRACE("IsUEFI : %s\n", m_bIsUefi ? "true" : "false"); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetActivePartitionStartingOffset Description : Reads the ActivePartitionStartingOffset key from parsed data and sets to the its data member. Parameters : [in] tree: parsed recovery config tree structure Return Code : None An exception will be thrown if bad value present for ActivePartitionStartingOffset key and IsUEFI is true. */ void AzureRecoveryConfig::SetActivePartitionStartingOffset(const conf_tree& tree) { TRACE_FUNC_BEGIN; std::string strValue; try { strValue = tree.get<std::string>(RecoveryConfigKey::ACTIVE_PARTITION_STARTING_OFFSET); if (!strValue.empty()) { m_activePartitionStartingOffset = boost::lexical_cast<long long>(strValue); } } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::ACTIVE_PARTITION_STARTING_OFFSET, exp.what()); // // this value is needed only in UEFI case. // if (m_bIsUefi) THROW_CONFIG_EXCEPTION("Could not read ActivePartitionOffset value from recovery config file."); } catch (boost::bad_lexical_cast& cast_exp) { TRACE_ERROR("Bad value in %s key\n", RecoveryConfigKey::ACTIVE_PARTITION_STARTING_OFFSET); if(m_bIsUefi) THROW_CONFIG_EXCEPTION("Bad ActivePartitionOffset value in recovery config file"); } TRACE("Active Partition Number: %s\n", strValue.c_str()); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetDiskSignature Description : Reads the LogLevel key from parsed data and sets to the its data member. Parameters : [in] tree: parsed recovery config tree structure Return Code : None An exception will be thrown if bad value present for Loglevel key. */ void AzureRecoveryConfig::SetDiskSignature(const conf_tree& tree) { TRACE_FUNC_BEGIN; try { m_diskSignature = tree.get<std::string>(RecoveryConfigKey::DISK_SIGNATURE); boost::trim(m_diskSignature); } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::DISK_SIGNATURE, exp.what()); } TRACE("DiskSignature: %s\n", m_diskSignature.c_str()); if (m_bIsUefi && m_diskSignature.empty()) THROW_CONFIG_EXCEPTION("DiskSignature value is empty or invalid in recovery config file"); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::SetFilesToDetectSystemPartitions. Description : Reads the SetFilesToDetectSystemPartitions key from parsed data and set to its data member. Parameters : [in] tree: parsed recovery config tree structure. Return Code : None */ void AzureRecoveryConfig::SetFilesToDetectSystemPartitions( const conf_tree& tree) { TRACE_FUNC_BEGIN; try { m_filesToDetectSystemPartitions = tree.get<std::string>( RecoveryConfigKey::FILES_TO_DETECT_SYS_PARTITION); boost::trim(m_filesToDetectSystemPartitions); } catch (const boost::property_tree::ptree_error& exp) { TRACE_WARNING("Read error for key %s. Exception: %s\n", RecoveryConfigKey::FILES_TO_DETECT_SYS_PARTITION, exp.what()); } TRACE_INFO("FilesToDetectSystemPartitions: %s\n", m_filesToDetectSystemPartitions.c_str()); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::Parse Description : Opens the recovery config file and parses its content. Parameters : [in] recovery_conf_file: recovery config file path Return Code : None An exception will be thrown on parsing failure. */ void AzureRecoveryConfig::Parse(const std::string& recovry_conf_file) { TRACE_FUNC_BEGIN; BOOST_ASSERT(!recovry_conf_file.empty()); boost::property_tree::ptree conf_ptree; boost::property_tree::read_ini(recovry_conf_file, conf_ptree); SetStatusBlobUri(conf_ptree); SetDiskMap(conf_ptree); SetSCSIHost(conf_ptree); SetSysMountPoint(conf_ptree); SetLogLevel(conf_ptree); SetNewHostId(conf_ptree); SetTestFailover(conf_ptree); SetEnableRDP(conf_ptree); SetIsUEFI(conf_ptree); SetActivePartitionStartingOffset(conf_ptree); SetDiskSignature(conf_ptree); SetFilesToDetectSystemPartitions(conf_ptree); m_bInitialized = true; TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::Init Description : Static method to initialize the singleton object Parameters : [in] recovery_conf_file: recovery config file path Return Code : None, An exception will be thrown on parsing failure or empty file name. */ void AzureRecoveryConfig::Init(const std::string& recovery_conf_file) { TRACE_FUNC_BEGIN; if (s_config_obj.m_bInitialized) { TRACE_WARNING("Recovery Config object is already initialized\n"); return; } if (recovery_conf_file.empty()) { THROW_CONFIG_EXCEPTION("Recovrey config file name should not be empty"); } s_config_obj.Parse(recovery_conf_file); TRACE_FUNC_END; } /* Method : AzureRecoveryConfig::Instance Description : static method to access the singleton obj instance Parameters : None Return Code : Singleton object reference */ const AzureRecoveryConfig& AzureRecoveryConfig::Instance() { if (!s_config_obj.m_bInitialized) { THROW_CONFIG_EXCEPTION("Recovery Config Obj is not Initiazlized"); } return s_config_obj; } /* Method : AzureRecoveryConfig::GetStatusBlobUri Description : Get method for blob-sas parsed from recovery config file Parameters : None Return Code : blob sas uri string */ std::string AzureRecoveryConfig::GetStatusBlobUri() const { BOOST_ASSERT(m_bInitialized); return m_blob_sas; } /* Method : AzureRecoveryConfig::GetDiskMap Description : Fills the disk-lun mapping information parsed from recovery config file to the out-param disk_map. Parameters : [out] disk_map : Filled with SourceDisk->LUN mapping data Return Code : None */ void AzureRecoveryConfig::GetDiskMap(disk_lun_map& disk_map) const { BOOST_ASSERT(m_bInitialized); disk_map.insert(m_disks.begin(), m_disks.end()); } /* Method : AzureRecoveryConfig::GetScsiHostNum Description : Returns the scsi host number on which the data disks appear on azure hydration-vm. On windows 3 is the default value. On Linux its 5. If 'ScsiHost' is set on recoveryconfig.conf file then that value will be returned. Parameters : None Return Code : Data disks SCSI Host number */ int AzureRecoveryConfig::GetScsiHostNum() const { BOOST_ASSERT(m_bInitialized); return m_scsiHost; } /* Method : AzureRecoveryConfig::GetLogLevel Description : Returns the log level for trace messages. Default value is 3 i.e Info Parameters : None Return Code : Log level for trace */ LogLevel AzureRecoveryConfig::GetLogLevel() const { BOOST_ASSERT(m_bInitialized); return m_logLevel; } /* Method : AzureRecoveryConfig::GetSysMountPoint Description : Returns the boot device identify specified in recovryconfig.conf file. If this value is present then the lookup will happen with this identity. Parameters : None Return Code : One of system mount point on linux, OS install drive letter on windows. */ std::string AzureRecoveryConfig::GetSysMountPoint() const { BOOST_ASSERT(m_bInitialized); return m_sysMountPoint; } /* Method : AzureRecoveryConfig::GetNewHostId Description : Returns the new host-id for recovering vm specified in recovryconfig.conf file. Parameters : None Return Code : uuid in string format */ std::string AzureRecoveryConfig::GetNewHostId() const { BOOST_ASSERT(m_bInitialized); return m_newHostId; } /* Method : AzureRecoveryConfig::IsTestFailover Description : Parameters : None Return Code : true if its a TestFailover, otherwise false. */ bool AzureRecoveryConfig::IsTestFailover() const { BOOST_ASSERT(m_bInitialized); return m_bTestFailover; } /* Method : AzureRecoveryConfig::EnableRDP Description : Parameters : None Return Code : true if user has selected Enable RDP option, otherwise false. */ bool AzureRecoveryConfig::EnableRDP() const { BOOST_ASSERT(m_bInitialized); return m_bEnableRDP; } /* Method : AzureRecoveryConfig::EnableRDP Description : Parameters : None Return Code : true if os disk was UEFI, otherwise false. */ bool AzureRecoveryConfig::IsUEFI() const { BOOST_ASSERT(m_bInitialized); return m_bIsUefi; } /* Method : AzureRecoveryConfig::GetActivePartitionStartingOffset Description : Parameters : None Return Code : Active partition StartingOffset, 0 on non-UEFI case. */ long long AzureRecoveryConfig::GetActivePartitionStartingOffset() const { BOOST_ASSERT(m_bInitialized); return m_activePartitionStartingOffset; } /* Method : AzureRecoveryConfig::GetDiskSignature Description : Parameters : None Return Code : disk signature of the converted UEFI Disk, empty string on non-UEFI case. */ std::string AzureRecoveryConfig::GetDiskSignature() const { BOOST_ASSERT(m_bInitialized); return m_diskSignature; } /* Method : AzureRecoveryConfig::GetFilesToDetectSystemPartitions Description : Parameters : None Return Code : Files to detect system partitions setting. */ std::string AzureRecoveryConfig::GetFilesToDetectSystemPartitions() const { BOOST_ASSERT(m_bInitialized); return m_filesToDetectSystemPartitions; } /* Method : AzureRecoveryConfig::PrintConfig Description : Prints the parsed confgiration to console and log files Parameters : None Return Code : None */ void AzureRecoveryConfig::PrintConfig() const { TRACE_FUNC_BEGIN; TRACE_INFO("Blob Sas Uri: %s\n", Instance().GetStatusBlobUri().c_str()); TRACE_INFO("[DiskMap]\n"); disk_lun_map disks; Instance().GetDiskMap(disks); for (disk_lun_cons_iter iter = disks.begin(); iter != disks.end(); iter++) TRACE_INFO("%s = %d\n", iter->first.c_str(), iter->second); TRACE_FUNC_END; } }