PRL_RESULT CDspHaClusterHelper::updateClusterResourceParams(const QString & sName,
		CVmHighAvailability *oldHa, CVmHighAvailability *newHa, const QString & newPath, PRL_VM_TYPE vmType)
{
	QProcess proc;
	QStringList args;
	QString cmd;

	PRL_ASSERT(oldHa);
	PRL_ASSERT(newHa);

	if (newHa->isEnabled() != oldHa->isEnabled())
		cmd = newHa->isEnabled() ? SHAMAN_CMD_ADD : SHAMAN_CMD_DEL;
	else if (newHa->getPriority() != oldHa->getPriority()) {
		cmd = SHAMAN_CMD_SET;
	} else {
		/* HA options are not changed */
		return PRL_ERR_SUCCESS;
	}

	/*
	 * Don't run shaman if HA is disabled in VM config and the command line
	 * doesn't contain '--ha-enable yes'.
	 */
	if ((newHa->isEnabled() == oldHa->isEnabled()) && !newHa->isEnabled())
		return PRL_ERR_SUCCESS;

	args += cmd;
	args += getResourcePrefix(vmType) + sName;

	if (cmd != SHAMAN_CMD_DEL) {
		/*
		 * Specify all parameters from the config when doing 'shaman add'.
		 * This is needed e.g. when registering an already existing VM - newly
		 * created cluster resource for this VM should contain all actual
		 * HA parameter values.
		 */
		if ((newHa->getPriority() != oldHa->getPriority()) || (cmd == SHAMAN_CMD_ADD)) {
			args += QString("--path");
			args += newPath;
			args += QString("--prio");
			args += QString("%1").arg(newHa->getPriority());
		}
	}

	PRL_RESULT res = runHaman(args, proc);
	if (PRL_FAILED(res))
		WRITE_TRACE(DBG_FATAL, "cluster resource '%s' registration error", QSTR2UTF8(sName));
	return res;
}
void CDspVmAutoTaskManagerBase::Init()
{
	WRITE_TRACE( DBG_DEBUG, "Initializing %s manager", getManagerName() );

	QMultiHash<QString , SmartPtr<CVmConfiguration> > hashAllVms
		= CDspService::instance()->getVmDirHelper().getAllVmList();

	QMultiHash<QString , SmartPtr<CVmConfiguration> >::iterator it;
	for(it = hashAllVms.begin(); it != hashAllVms.end(); ++it)
	{
		SmartPtr<CVmConfiguration> pVmConfig = it.value();
		PRL_ASSERT(pVmConfig);

		if (isEnabled(pVmConfig, true))
		{
			PRL_RESULT res = tryToRegisterVm(pVmConfig, it.key());
			if (PRL_FAILED(res))
				WRITE_TRACE(DBG_FATAL,
					"Can't register VM %s in Auto-task Manager during starting dispetcher."
					"Error: 0x%x, (%s).",
					QSTR2UTF8(pVmConfig->getVmIdentification()->getVmUuid()),
					res, PRL_RESULT_TO_STRING(res) );
		}
	}

	m_bInitialized = true;
}
Task_MigrateCtSource::Task_MigrateCtSource(
		const SmartPtr<CDspClient>& client,
		const CProtoCommandPtr cmd,
		const SmartPtr<IOPackage>& p)
    :
	CDspTaskHelper(client, p),
	Task_DispToDispConnHelper(getLastError()),
	m_pVmConfig(new CVmConfiguration()),
	m_bNewVmInstance(false),
	m_nSteps(0),
	m_nTotalSize(0),
	m_pOpaqueLock(NULL)
{
	CProtoVmMigrateCommand *pCmd = CProtoSerializer::CastToProtoCommand<CProtoVmMigrateCommand>(cmd);
	PRL_ASSERT(pCmd->IsValid());
	m_sVmUuid = pCmd->GetVmUuid();
	m_sServerHostname = pCmd->GetTargetServerHostname();
	m_nServerPort = pCmd->GetTargetServerPort();
	if (m_nServerPort == 0)
		m_nServerPort = CDspService::getDefaultListenPort();
	m_sServerSessionUuid = pCmd->GetTargetServerSessionUuid();
	m_sTargetServerCtHomePath = pCmd->GetTargetServerVmHomePath();
	m_nMigrationFlags = pCmd->GetMigrationFlags();
	m_nReservedFlags = pCmd->GetReservedFlags();
	m_bExVmOperationRegistered = false;
}
void Task_MigrateCtTarget::handlePackage(IOSender::Handle h, const SmartPtr<IOPackage> p)
{
	PRL_RESULT nRetCode;
	bool bExit;
	PRL_ASSERT(m_pVmMigrateTarget.getImpl());

	// #439777 to protect call handler for destroying object
	WaiterTillHandlerUsingObject::AutoUnlock lock( m_waiter );
	if( !lock.isLocked() )
		return;

	if (h != m_pStartDispConnection->GetConnectionHandle())
		return;

	if (IS_FILE_COPY_PACKAGE(p->header.type)) {
		nRetCode = m_pVmMigrateTarget->handlePackage(p, &bExit);
		if (bExit)
			QThread::exit(nRetCode);
	} else if (p->header.type == VmMigrateCancelCmd) {
		WRITE_TRACE(DBG_DEBUG, "Migration was cancelled");
		QThread::exit(PRL_ERR_OPERATION_WAS_CANCELED);
	} else {
		WRITE_TRACE(DBG_FATAL, "Invalid package type %d, ignored", p->header.type);
	}
}
PRL_RESULT CDspHaClusterHelper::addClusterResource(const QString & sName,
		const CVmHighAvailability *ha, const QString & sPath)
{
	PRL_ASSERT(ha);

	if (!ha->isEnabled())
		return PRL_ERR_SUCCESS;

	// handle only VM on shared FS - nfs, gfs, gfs2, pcs
	if (!CFileHelper::isSharedFS(sPath))
		return PRL_ERR_SUCCESS;

	QProcess proc;
	QStringList args;
	args += SHAMAN_CMD_ADD;
	args += getResourcePrefix() + sName;
	args += QString("--prio");
	args += QString("%1").arg(ha->getPriority());
	args += QString("--path");
	args += sPath;
	args += QString("--force");

	PRL_RESULT res = runHaman(args, proc);
	if (PRL_FAILED(res))
		WRITE_TRACE(DBG_FATAL, "cluster resource '%s' registration error", QSTR2UTF8(sName));
	return res;
}
void CDspIOCtClientHandler::handleFromDispatcherPackage (
	const SmartPtr<CDspHandler>&,
	const IOSender::Handle&,
	const SmartPtr<IOPackage>& )
{
	// Never should be called for this handler
	PRL_ASSERT(0);
}
void Task_EventLoopBase::cancelOperation(
    SmartPtr<CDspClient> user, const SmartPtr<IOPackage>& pkg)
{
    bool invoked = true;
    invoked &= QMetaObject::invokeMethod(this, "taskCancel", Qt::QueuedConnection);
    PRL_ASSERT(invoked);

    CDspTaskHelper::cancelOperation(user, pkg);
}
PRL_RESULT Task_EventLoopBase::run_body()
{
    bool invoked = true;
    invoked &= QMetaObject::invokeMethod(this, "onFirstEvent", Qt::QueuedConnection);
    PRL_ASSERT(invoked);

    QThread::exec();
    return getLastErrorCode();
}
/**
* Class constructor
*/
CDspHwMonitorHandler::CDspHwMonitorHandler( QObject * parent )
			: QThread (parent),
			m_hResetEvent(INVALID_HANDLE_VALUE),
			m_FinalizationMutex(QMutex::Recursive)
{
	g_pHwMonitorHandler = this;

	/* Event to stop HWMonitor */
	m_hResetEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
	if (m_hResetEvent == INVALID_HANDLE_VALUE)
		WRITE_TRACE(DBG_FATAL, "Failed to create StopEvent");

	PRL_ASSERT(m_hResetEvent != INVALID_HANDLE_VALUE);
}
PRL_RESULT Task_SyncVmsUptime::run_body()
{
	quint32 nTimeout =
		CDspService::instance()->getDispConfigGuard().getDispWorkSpacePrefs()->getVmUptimeSyncTimeoutInMinutes();
	if ( ! nTimeout )
	{
		WRITE_TRACE(DBG_FATAL, "Synchronization up time task was not started due to timeout is zero !");
		return (PRL_ERR_SUCCESS);
	}

	SmartPtr<QTimer> pTimer(new QTimer);
	bool bConnected = connect(pTimer.getImpl(), SIGNAL(timeout()), SLOT(onTimeoutEvent()));
	PRL_ASSERT(bConnected);
	pTimer->start(nTimeout*60*1000);
	exec();
	return (PRL_ERR_SUCCESS);
}
PRL_RESULT CDspHaClusterHelper::renameClusterResource(const QString & oldName,
		CVmHighAvailability *oldHa, const QString & newName, const QString & newPath)
{
	PRL_ASSERT(oldHa);

	if (!oldHa->isEnabled())
		return PRL_ERR_SUCCESS;

	PRL_RESULT res = addClusterResource(newName, oldHa, newPath);
	if (PRL_FAILED(res))
		return res;

	/* Ignore errors on remove, can't do anything with them. */
	removeClusterResource(oldName);

	return PRL_ERR_SUCCESS;
}
PRL_RESULT Task_MigrateCtTarget::migrateStoppedVm()
{
	PRL_RESULT nRetCode = PRL_ERR_SUCCESS;
	CDispToDispCommandPtr pReply;
	SmartPtr<IOPackage> pPackage;

	m_pSender = SmartPtr<CVmFileListCopySender>(new CVmFileListCopySenderServer(
			CDspService::instance()->getIOServer(),
			m_pStartDispConnection->GetConnectionHandle()));

	/* CVmFileListCopyTarget will use Vm uuid in progress messages for clients, so will use original Vm uuid */
	m_pVmMigrateTarget = SmartPtr<CVmFileListCopyTarget>(
		new CVmFileListCopyTarget(m_pSender.getImpl(), m_sOriginVmUuid, m_sTargetVmHomePath, NULL, m_nTimeout));


	// Connect to handle traffic report package
	bool bConnected = QObject::connect(
		m_pStartDispConnection.getImpl(),
		SIGNAL(onPackageReceived(IOSender::Handle, const SmartPtr<IOPackage>)),
		SLOT(handlePackage(IOSender::Handle, const SmartPtr<IOPackage>)),
		Qt::DirectConnection );
	PRL_ASSERT(bConnected);

	// set empty string for default path
	pReply = CDispToDispProtoSerializer::CreateVmMigrateReply(QString());
	pPackage = DispatcherPackage::createInstance(
		pReply->GetCommandId(), pReply->GetCommand()->toString(), m_pStartPackage);
	m_pStartDispConnection->sendPackage(pPackage);

	nRetCode = QThread::exec();

	QObject::disconnect(
		m_pStartDispConnection.getImpl(),
		SIGNAL(onPackageReceived(IOSender::Handle, const SmartPtr<IOPackage>)),
		this,
		SLOT(handlePackage(IOSender::Handle, const SmartPtr<IOPackage>)));

	if (PRL_FAILED(nRetCode))
		return nRetCode;

	return PRL_ERR_SUCCESS;
}
Task_MigrateCtTarget::Task_MigrateCtTarget(
	const QObject *parent,
	const SmartPtr<CDspDispConnection> &pDispConnection,
	CDispToDispCommandPtr pCmd,
	const SmartPtr<IOPackage> &p)
   :
	CDspTaskHelper(pDispConnection->getUserSession(), p),
	Task_DispToDispConnHelper(getLastError()),
	m_pParent(parent),
	m_pCheckDispConnection(pDispConnection),
	m_pCheckPackage(p),
	m_cDstHostInfo(CDspService::instance()->getHostInfo()->data()),
	m_pOpaqueLock(NULL),
	m_nSteps(0),
	m_nBundlePermissions(0),
	m_nConfigPermissions(0)
{
	CVmMigrateCheckPreconditionsCommand * pCheckCmd =
		CDispToDispProtoSerializer::CastToDispToDispCommand<CVmMigrateCheckPreconditionsCommand>(pCmd);

	m_hConnHandle = pDispConnection->GetConnectionHandle();
	m_nMigrationFlags = pCheckCmd->GetMigrationFlags();
	m_nReservedFlags = pCheckCmd->GetReservedFlags();
	m_nVersion = pCheckCmd->GetVersion();
	m_sVmConfig = pCheckCmd->GetVmConfig();
	m_nPrevVmState = pCheckCmd->GetVmPrevState();
	m_sVmDirPath = pCheckCmd->GetTargetVmHomePath();
	m_sSrcHostInfo = pCheckCmd->GetSourceHostHardwareInfo();

	/* initialize all vars from pCheckCmd - after exit from constructor package buffer will invalid */

	bool bConnected = QObject::connect(
		&CDspService::instance()->getIOServer(),
		SIGNAL(onClientDisconnected(IOSender::Handle)),
		SLOT(clientDisconnected(IOSender::Handle)),
		Qt::DirectConnection);
	PRL_ASSERT(bConnected);
}
PRL_RESULT Task_MigrateCtTarget::run_body()
{
	PRL_RESULT nRetCode = PRL_ERR_SUCCESS;
	bool bConnected;
	QTimer *pTimer;
	CDispToDispCommandPtr pReply;
	SmartPtr<IOPackage> pPackage;
	IOSendJob::Handle hJob;

	if (operationIsCancelled()) {
		nRetCode = PRL_ERR_OPERATION_WAS_CANCELED;
		goto exit;
	}

	bConnected = QObject::connect(m_pParent,
		SIGNAL(onPackageReceived(
			const SmartPtr<CDspDispConnection> &,
			const QString &,
			const SmartPtr<IOPackage> &)),
		SLOT(handleStartPackage(
			const SmartPtr<CDspDispConnection> &,
			const QString &,
			const SmartPtr<IOPackage> &)),
		Qt::DirectConnection);
	PRL_ASSERT(bConnected);

	m_nReservedFlags |= PVM_CT_MIGRATE;
	pReply = CDispToDispProtoSerializer::CreateVmMigrateCheckPreconditionsReply(
		m_lstCheckPrecondsErrors, QStringList(), m_nReservedFlags);
	pPackage =
		DispatcherPackage::createInstance(
			pReply->GetCommandId(), pReply->GetCommand()->toString(), m_pCheckPackage);
	hJob = m_pCheckDispConnection->sendPackage(pPackage);
	if (!hJob.isValid()) {
		nRetCode = PRL_ERR_OPERATION_FAILED;
		goto exit;
	}

	/* set timer */
	pTimer = new QTimer();
	pTimer->setSingleShot(true);
	bConnected = QObject::connect(pTimer, SIGNAL(timeout()), SLOT(handleStartCommandTimeout()), Qt::DirectConnection);
	pTimer->start(VM_MIGRATE_START_CMD_WAIT_TIMEOUT);

	/* will wait StartMigration command */
	nRetCode = exec();
	pTimer->stop();
	if (bConnected)
		QObject::disconnect(pTimer, SIGNAL(timeout()), this, SLOT(handleStartCommandTimeout()));
	delete pTimer;

	QObject::disconnect(m_pParent,
		SIGNAL(onPackageReceived(
			const SmartPtr<CDspDispConnection> &,
			const QString &,
			const SmartPtr<IOPackage> &)),
		this,
		SLOT(handleStartPackage(
			const SmartPtr<CDspDispConnection> &,
			const QString &,
			const SmartPtr<IOPackage> &)));

	if (PRL_FAILED(nRetCode))
		goto exit;

	if (operationIsCancelled()) {
		nRetCode = PRL_ERR_OPERATION_WAS_CANCELED;
		goto exit;
	}

	if ( !(m_nReservedFlags & PVM_DONT_COPY_VM) ) {
		/* to create Vm bundle */
		if (!CFileHelper::WriteDirectory(m_sTargetVmHomePath, &getClient()->getAuthHelper())) {
			nRetCode = PRL_ERR_BACKUP_CANNOT_CREATE_DIRECTORY;
			CVmEvent *pEvent = getLastError();
			pEvent->setEventCode(nRetCode);
			pEvent->addEventParameter(
				new CVmEventParameter(PVE::String, m_sTargetVmHomePath, EVT_PARAM_MESSAGE_PARAM_0));
			WRITE_TRACE(DBG_FATAL, "[%s] Cannot create \"%s\" directory",
					__FUNCTION__, QSTR2UTF8(m_sTargetVmHomePath));
			goto exit;
		}
		/* set original permissions to Vm bundle (https://jira.sw.ru/browse/PSBM-8269) */
		if (m_nBundlePermissions) {
			QFile vmBundle(m_sTargetVmHomePath);
			if (!vmBundle.setPermissions((QFile::Permissions)m_nBundlePermissions)) {
				WRITE_TRACE(DBG_FATAL,
					"[%s] Cannot set permissions for Vm bundle \"%s\", will use default",
					__FUNCTION__, QSTR2UTF8(m_sTargetVmHomePath));
			}
		}
	}
	m_nSteps |= MIGRATE_STARTED;
	if ((m_nPrevVmState == VMS_RUNNING) || (m_nPrevVmState == VMS_PAUSED)) {
		nRetCode = PRL_ERR_VM_MIGRATE_UNSUITABLE_VM_STATE;
	} else {
		nRetCode = migrateStoppedVm();

		/* migration completed and connection state is indifferent for us
		   https://jira.sw.ru/browse/PSBM-8925 */
		QObject::disconnect(
			&CDspService::instance()->getIOServer(),
			SIGNAL(onClientDisconnected(IOSender::Handle)),
			this,
			SLOT(clientDisconnected(IOSender::Handle)));
	}

	if (PRL_FAILED(nRetCode))
		goto exit;

	/* rename conf file since source sent it with his origin ctid */
	if (m_nOriginCtid != m_nCtid) {
		QString srcPath = m_sTargetVmHomePath + QString("/%1.conf").arg(m_nOriginCtid);
		QString dstPath = m_sTargetVmHomePath + QString("/%1.conf").arg(m_nCtid);
		QFile::rename(srcPath, dstPath);
	}

	nRetCode = CVzHelper::dst_complete_migrate_env(m_sVmUuid, m_nCtid, m_nOriginCtid, &m_pOpaqueLock);
	if (PRL_FAILED(nRetCode)) {
		WRITE_TRACE(DBG_FATAL, "Can not compelete destination CT migration for ctid %u uuid %s",
			    m_nCtid,  QSTR2UTF8(m_sVmUuid));
		goto exit;
	}

	if (PVMT_CLONE_MODE & getRequestFlags())
		m_pVmConfig->getVmIdentification()->setSourceVmUuid(m_sOriginVmUuid);

	if (PVMT_CLONE_MODE & getRequestFlags()) {
		if ( PVMT_SWITCH_TEMPLATE & getRequestFlags() )
			m_pVmConfig->getVmSettings()->getVmCommonOptions()->setTemplate(
				!m_pVmConfig->getVmSettings()->getVmCommonOptions()->isTemplate() );

		Task_CloneVm::ResetNetSettings(m_pVmConfig);
	}

	/* do not fail since here - Ct already migrated */
	{
		QString sServerUuid = CDspService::instance()->getDispConfigGuard().getDispConfig()
			->getVmServerIdentification()->getServerUuid();
		QString sLastServerUuid = m_pVmConfig->getVmIdentification()->getServerUuid();
		m_pVmConfig->getVmIdentification()->setServerUuid(sServerUuid);
		m_pVmConfig->getVmIdentification()->setLastServerUuid(sLastServerUuid);
		SmartPtr<CVmConfiguration> pOldConfig = CDspService::instance()->getVzHelper()
			->getVzlibHelper().get_env_config(m_nCtid);
		if (pOldConfig == NULL) {
			WRITE_TRACE(DBG_FATAL, "Can't get config for CT %s [%d]", QSTR2UTF8(m_sVmUuid), m_nCtid);
		} else {
			get_op_helper().apply_env_config(m_pVmConfig, pOldConfig);
		}
	}

	// insert new item in user's VM Directory
	m_pVmConfig = CDspService::instance()->getVzHelper()->getVzlibHelper().get_env_config(m_nCtid);
	if (PRL_FAILED(CDspService::instance()->getVzHelper()->insertVmDirectoryItem(m_pVmConfig))) {
		WRITE_TRACE(DBG_FATAL, "Can't insert CT to VmDirectory by error %#x, %s",
			    nRetCode, PRL_RESULT_TO_STRING(nRetCode) );
	}

exit:
	setLastErrorCode(nRetCode);
	return nRetCode;
}
PRL_RESULT Mixin_CreateVmSupport::setDefaultVmPermissions(
	SmartPtr<CDspClient> pUser,
	QString vmPathToConfig,
	bool bKeepOthersPermissions
)
{
	PRL_ASSERT( pUser );
	PRL_ASSERT( ! vmPathToConfig.isEmpty() );

	if( ! pUser || vmPathToConfig.isEmpty() )
		return PRL_ERR_INVALID_ARG;

	// FIXME: isFsSupportPermsAndOwner() should be moved near setFullAccessRightsToVm() and united with it.
	{
		//https://bugzilla.sw.ru/show_bug.cgi?id=267152
		CAuthHelperImpersonateWrapper _impersonate( &pUser->getAuthHelper() );

		// # https://bugzilla.sw.ru/show_bug.cgi?id=112901
		// https://jira.sw.ru/browse/PSBM-9040
		if( !CFileHelper::isFsSupportPermsAndOwner( vmPathToConfig ) )
		{
			WRITE_TRACE(DBG_FATAL, "File system does not support permissions. Setting default Vm permission will be ignored. (path=%s)"
				, QSTR2UTF8( vmPathToConfig ) );
			return PRL_ERR_SUCCESS;
		}
	}

	// get vm directory path

	// To prevent stupid errors see https://bugzilla.sw.ru/show_bug.cgi?id=483700 for more details
	PRL_ASSERT(QFileInfo( vmPathToConfig ).isFile());
	QString strVmDirPath;
	if ( QFileInfo( vmPathToConfig ).isFile() )
		strVmDirPath = CFileHelper::GetFileRoot( vmPathToConfig );
	else
	{
		strVmDirPath = vmPathToConfig;
		vmPathToConfig = QString("%1/%2").arg(strVmDirPath).arg(VMDIR_DEFAULT_VM_CONFIG_FILE);
	}

	if ( !CDspAccessManager::setOwner( strVmDirPath, &pUser->getAuthHelper(), true )  )
	{
		WRITE_TRACE(DBG_FATAL, "Can't change owner to vm dir files [%s]. error=[%s]"
			, QSTR2UTF8( strVmDirPath )
			, QSTR2UTF8( Prl::GetLastErrorAsString() ) );
		return PRL_ERR_CANT_CHANGE_OWNER_OF_FILE;
	}

	//////////////////////////////////////////////////////////////////////////
	// set default access rigths
	//////////////////////////////////////////////////////////////////////////
	CVmDirectoryItem vmDirItem;
	vmDirItem.setVmHome( vmPathToConfig );
	PRL_SEC_AM ownerAccess = CDspAccessManager::VmAccessRights::makeModeRWX() ;
	PRL_SEC_AM otherAccess = CDspAccessManager::VmAccessRights::makeModeNO_ACCESS() ;

	PRL_RESULT err = CDspService::instance()->getAccessManager()
		.setFullAccessRightsToVm( pUser, &vmDirItem, &ownerAccess,
		// Do not change others permissions during registration at desktop mode
		// https://bugzilla.sw.ru/show_bug.cgi?id=120191
		 ! bKeepOthersPermissions ? &otherAccess : NULL );
	if( PRL_FAILED( err ) )
	{
		WRITE_TRACE(DBG_FATAL, "Can't change permission to vm dir files [%s]. error=[%s]"
			, QSTR2UTF8( strVmDirPath )
			, QSTR2UTF8( Prl::GetLastErrorAsString() ) );
		return PRL_ERR_CANT_CHANGE_FILE_PERMISSIONS;
	}

	return PRL_ERR_SUCCESS;
}