Beispiel #1
0
    def checkDependencies(self, productPackageFile):
        for dependency in productPackageFile.packageControlFile.getPackageDependencies(
        ):
            productOnDepots = self._depotBackend._context.productOnDepot_getObjects(
                depotId=self._depotBackend._depotId,
                productId=dependency['package'])
            if not productOnDepots:
                raise BackendUnaccomplishableError(
                    u"Dependent package '%s' not installed" %
                    dependency['package'])

            if not dependency['version']:
                logger.info(u"Fulfilled product dependency '%s'" % dependency)
                continue

            productOnDepot = productOnDepots[0]
            availableVersion = productOnDepot.getProductVersion(
            ) + u'-' + productOnDepot.getPackageVersion()

            if compareVersions(availableVersion, dependency['condition'],
                               dependency['version']):
                logger.info(
                    u"Fulfilled package dependency %s (available version: %s)"
                    % (dependency, availableVersion))
            else:
                raise BackendUnaccomplishableError(
                    u"Unfulfilled package dependency %s (available version: %s)"
                    % (dependency, availableVersion))
Beispiel #2
0
 def _getHostAddress(self, host):
     address = None
     if self._resolveHostAddress:
         try:
             address = socket.gethostbyname(host.id)
         except socket.error as lookupError:
             logger.debug2("Failed to lookup ip address for {0}: {1!r}",
                           host.id, lookupError)
     if not address:
         address = host.ipAddress
     if not address and not self._resolveHostAddress:
         try:
             address = socket.gethostbyname(host.id)
         except socket.error:
             raise BackendUnaccomplishableError(
                 u"Failed to resolve ip address for host '%s'" % host.id)
     if not address:
         raise BackendUnaccomplishableError(
             u"Failed to get ip address for host '%s'" % host.id)
     return address
Beispiel #3
0
 def _getResponsibleDepotId(self, clientId):
     configStates = self._context.configState_getObjects(
         configId=u'clientconfig.depot.id', objectId=clientId)  # pylint: disable=maybe-no-member
     if configStates and configStates[0].values:
         depotId = configStates[0].values[0]
     else:
         configs = self._context.config_getObjects(
             id=u'clientconfig.depot.id')  # pylint: disable=maybe-no-member
         if not configs or not configs[0].defaultValues:
             raise BackendUnaccomplishableError(
                 u"Failed to get depotserver for client '%s', config 'clientconfig.depot.id' not set and no defaults found"
                 % clientId)
         depotId = configs[0].defaultValues[0]
     return depotId
Beispiel #4
0
    def _updateMasterFromWorkBackend(self, modifications=[]):  # pylint: disable=dangerous-default-value,too-many-locals,too-many-statements
        modifiedObjects = collections.defaultdict(list)
        logger.notice("Updating master from work backend (%d modifications)",
                      len(modifications))

        for modification in modifications:
            try:
                ObjectClass = eval(modification['objectClass'])  # pylint: disable=eval-used
                identValues = modification['ident'].split(
                    ObjectClass.identSeparator)
                identAttributes = get_ident_attributes(ObjectClass)
                objectFilter = {}
                for index, attribute in enumerate(identAttributes):
                    if index >= len(identValues):
                        raise BackendUnaccomplishableError(
                            f"Bad ident '{identValues}' for objectClass '{modification['objectClass']}'"
                        )

                    objectFilter[attribute] = identValues[index]

                backend = self._snapshotBackend if modification[
                    "command"] == "delete" else self._workBackend
                meth = getattr(backend,
                               ObjectClass.backendMethodPrefix + '_getObjects')
                objects = meth(**objectFilter)
                if objects:
                    modification['object'] = objects[0]
                    modifiedObjects[modification['objectClass']].append(
                        modification)
                    logger.debug("Modified object appended: %s", modification)
            except Exception as modify_error:  # pylint: disable=broad-except
                logger.error("Failed to sync backend modification %s: %s",
                             modification,
                             modify_error,
                             exc_info=True)
                continue

        if 'AuditHardwareOnHost' in modifiedObjects:
            self._masterBackend.auditHardwareOnHost_setObsolete(self._clientId)
            self._masterBackend.auditHardwareOnHost_updateObjects([
                mo['object'] for mo in modifiedObjects['AuditHardwareOnHost']
            ])

        if 'AuditSoftware' in modifiedObjects:
            self._masterBackend.auditSoftware_updateObjects(
                [mo['object'] for mo in modifiedObjects['AuditSoftware']])

        if 'AuditSoftwareOnClient' in modifiedObjects:
            self._masterBackend.auditSoftwareOnClient_setObsolete(
                self._clientId)
            self._masterBackend.auditSoftwareOnClient_updateObjects([
                mo['object'] for mo in modifiedObjects['AuditSoftwareOnClient']
            ])

        if 'ProductOnClient' in modifiedObjects:

            def objectsDifferFunction(snapshotObj, masterObj):
                return objects_differ(snapshotObj,
                                      masterObj,
                                      exclude_attributes=[
                                          'modificationTime', 'actionProgress',
                                          'actionResult', 'lastAction'
                                      ])

            def createUpdateObjectFunction(modifiedObj):
                return modifiedObj.clone(identOnly=False)

            def mergeObjectsFunction(snapshotObj, updateObj, masterObj,
                                     snapshotBackend, workBackend,
                                     masterBackend):  # pylint: disable=unused-argument,too-many-arguments
                masterVersions = sorted([
                    f"{p.productVersion}-{p.packageVersion}"
                    for p in masterBackend.productOnDepot_getObjects(
                        ["productVersion", "packageVersion"],
                        productId=snapshotObj.productId,
                        depotId=self._depotId)
                ])
                snapshotVersions = sorted([
                    f"{p.productVersion}-{p.packageVersion}"
                    for p in snapshotBackend.productOnDepot_getObjects(
                        ["productVersion", "packageVersion"],
                        productId=snapshotObj.productId,
                        depotId=self._depotId)
                ])

                logger.info(
                    "Syncing ProductOnClient %s (product versions local=%s, server=%s)",
                    updateObj, snapshotVersions, masterVersions)
                if snapshotVersions != masterVersions:
                    logger.notice(
                        "Product %s changed on server since last sync, not updating actionRequest (local=%s, server=%s)",
                        snapshotObj.productId, snapshotVersions,
                        masterVersions)
                    updateObj.actionRequest = None
                    updateObj.targetConfiguration = None
                return updateObj

            logger.debug("Syncing modified ProductOnClients with master: %s",
                         modifiedObjects['ProductOnClient'])
            self._syncModifiedObjectsWithMaster(
                ProductOnClient, modifiedObjects['ProductOnClient'],
                {"clientId": self._clientId}, objectsDifferFunction,
                createUpdateObjectFunction, mergeObjectsFunction)

        if 'LicenseOnClient' in modifiedObjects:

            def objectsDifferFunction(snapshotObj, masterObj):  # pylint: disable=function-redefined
                return objects_differ(snapshotObj, masterObj)

            def createUpdateObjectFunction(modifiedObj):  # pylint: disable=function-redefined
                return modifiedObj.clone(identOnly=False)

            def mergeObjectsFunction(snapshotObj, updateObj, masterObj,
                                     snapshotBackend, workBackend,
                                     masterBackend):  # pylint: disable=function-redefined,unused-argument,too-many-arguments
                return updateObj

            self._syncModifiedObjectsWithMaster(
                LicenseOnClient, modifiedObjects['LicenseOnClient'],
                {"clientId": self._clientId}, objectsDifferFunction,
                createUpdateObjectFunction, mergeObjectsFunction)

        for objectClassName in ('ProductPropertyState', 'ConfigState'):

            def objectsDifferFunction(snapshotObj, masterObj):  # pylint: disable=function-redefined
                return objects_differ(snapshotObj, masterObj)

            def createUpdateObjectFunction(modifiedObj):  # pylint: disable=function-redefined
                return modifiedObj.clone()

            def mergeObjectsFunction(snapshotObj, updateObj, masterObj,
                                     snapshotBackend, workBackend,
                                     masterBackend):  # pylint: disable=function-redefined,unused-argument,too-many-arguments
                if len(snapshotObj.values) != len(masterObj.values):
                    logger.info(
                        "Values of %s changed on server since last sync, not updating values",
                        snapshotObj)
                    return None

                if snapshotObj.values:
                    for val in snapshotObj.values:
                        if val not in masterObj.values:
                            logger.info(
                                "Values of %s changed on server since last sync, not updating values",
                                snapshotObj)
                            return None

                if masterObj.values:
                    for val in masterObj.values:
                        if val not in snapshotObj.values:
                            logger.info(
                                "Values of %s changed on server since last sync, not updating values",
                                snapshotObj)
                            return None

                return updateObj

            if objectClassName in modifiedObjects:
                self._syncModifiedObjectsWithMaster(
                    eval(objectClassName),  # pylint: disable=eval-used
                    modifiedObjects[objectClassName],
                    {"objectId": self._clientId},
                    objectsDifferFunction,
                    createUpdateObjectFunction,
                    mergeObjectsFunction)
Beispiel #5
0
	def productProperty_insertObject(self, productProperty):
		self._requiresEnabledSQLBackendModule()
		ConfigDataBackend.productProperty_insertObject(self, productProperty)
		data = self._objectToDatabaseHash(productProperty)
		possibleValues = data.pop('possibleValues') or []
		defaultValues = data.pop('defaultValues') or []

		where = self._uniqueCondition(productProperty)
		if self._sql.getRow('select * from `PRODUCT_PROPERTY` where %s' % where):
			self._sql.update('PRODUCT_PROPERTY', where, data, updateWhereNone=True)
		else:
			self._sql.insert('PRODUCT_PROPERTY', data)

		with closingConnectionAndCursor(self._sql) as (conn, cursor):
			retries = 10
			for retry in range(retries):
				try:
					# transaction
					cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE")
					with disableAutoCommit(self._sql):
						logger.debug2(u'Start Transaction: delete from ppv #{}', retry)
						conn.begin()
						self._sql.delete('PRODUCT_PROPERTY_VALUE', where, conn, cursor)
						conn.commit()
						logger.debug2(u'End Transaction')
						break
				except Exception as deleteError:
					logger.debug(u"Execute error: {}", deleteError)
					if deleteError.args[0] == DEADLOCK_FOUND_WHEN_TRYING_TO_GET_LOCK_ERROR_CODE:
						logger.debug(
							u'Table locked (Code {}) - restarting Transaction',
							DEADLOCK_FOUND_WHEN_TRYING_TO_GET_LOCK_ERROR_CODE
						)
						time.sleep(0.1)
					else:
						logger.error(u'Unknown DB Error: {!r}', deleteError)
						raise
			else:
				errorMessage = u'Table locked (Code {}) - giving up after {} retries'.format(
					DEADLOCK_FOUND_WHEN_TRYING_TO_GET_LOCK_ERROR_CODE,
					retries
				)
				logger.error(errorMessage)
				raise BackendUnaccomplishableError(errorMessage)

		with closingConnectionAndCursor(self._sql) as (conn, cursor):
			for value in possibleValues:
				# transform arguments for sql
				# from uniqueCondition
				if value in defaultValues:
					myPPVdefault = u"`isDefault` = 1"
				else:
					myPPVdefault = u"`isDefault` = 0"

				if isinstance(value, bool):
					if value:
						myPPVvalue = u"`value` = 1"
					else:
						myPPVvalue = u"`value` = 0"
				elif isinstance(value, (float, long, int)):
					myPPVvalue = u"`value` = %s" % (value)
				else:
					myPPVvalue = u"`value` = '%s'" % (self._sql.escapeApostrophe(self._sql.escapeBackslash(value)))
				myPPVselect = (
					u"select * from PRODUCT_PROPERTY_VALUE where "
					u"`propertyId` = '{0}' AND `productId` = '{1}' AND "
					u"`productVersion` = '{2}' AND "
					u"`packageVersion` = '{3}' AND {4} AND {5}".format(
						data['propertyId'],
						data['productId'],
						str(data['productVersion']),
						str(data['packageVersion']),
						myPPVvalue,
						myPPVdefault
					)
				)

				retries = 10
				for retry in range(retries):
					try:
						# transaction
						cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE")
						with disableAutoCommit(self._sql):
							logger.debug2(u'Start Transaction: insert to ppv #{}', retry)
							conn.begin()
							if not self._sql.getRow(myPPVselect, conn, cursor):
								self._sql.insert('PRODUCT_PROPERTY_VALUE', {
									'productId': data['productId'],
									'productVersion': data['productVersion'],
									'packageVersion': data['packageVersion'],
									'propertyId': data['propertyId'],
									'value': value,
									'isDefault': bool(value in defaultValues)
									}, conn, cursor)
								conn.commit()
							else:
								conn.rollback()
							logger.debug2(u'End Transaction')
							break
					except Exception as insertError:
						logger.debug(u"Execute error: {!r}", insertError)
						if insertError.args[0] == DEADLOCK_FOUND_WHEN_TRYING_TO_GET_LOCK_ERROR_CODE:
							# 1213: May be table locked because of concurrent access - retrying
							logger.notice(
								u'Table locked (Code {}) - restarting Transaction'.format(
									DEADLOCK_FOUND_WHEN_TRYING_TO_GET_LOCK_ERROR_CODE
								)
							)
							time.sleep(0.1)
						else:
							logger.error(u'Unknown DB Error: {!r}', insertError)
							raise
				else:
					errorMessage = u'Table locked (Code {}) - giving up after {} retries'.format(
						DEADLOCK_FOUND_WHEN_TRYING_TO_GET_LOCK_ERROR_CODE,
						retries
					)
					logger.error(errorMessage)
					raise BackendUnaccomplishableError(errorMessage)