def testGettingBackendManagerWithCustomConfig(tempDir):
    backendsDir = os.path.join(tempDir, 'backendsss')
    bmDir = os.path.join(tempDir, 'bm')
    dispatchConfig = os.path.join(bmDir, 'dispatch.conf')
    extensionDir = os.path.join(bmDir, 'extension')

    os.mkdir(bmDir)
    os.mkdir(extensionDir)
    os.mkdir(backendsDir)

    with open(dispatchConfig, 'w') as dpconf:
        dpconf.write("""
.* : file
""")

    kwargs = {
        "dispatchConfigFile": dispatchConfig,
        "backendConfigDir": backendsDir,
        "extensionConfigDir": extensionDir,
    }

    with getFileBackend(path=tempDir):
        # We need to make sure there is a file.conf for the backend.
        os.link(os.path.join(tempDir, 'etc', 'opsi', 'backends', 'file.conf'),
                os.path.join(backendsDir, 'file.conf'))

    backend = BackendManager(**kwargs)
    assert backend.backend_info()
def testGettingBackendManagerWithDefaultConfig():
    requiredPaths = (
        u'/etc/opsi/backendManager/dispatch.conf',
        u'/etc/opsi/backends',
        u'/etc/opsi/backendManager/extend.d',
        u'/var/lib/opsi/config/depots',
    )

    for path in requiredPaths:
        if not os.path.exists(path):
            pytest.skip("Missing {0}".format(path))

    backend = BackendManager()
    assert backend.backend_info()
Ejemplo n.º 3
0
def backendManager(_serverBackend, tempDir):
    """
    Returns an `OPSI.Backend.BackendManager.BackendManager` for testing.

    The returned instance is set up to have access to backend extensions.
    """
    defaultConfigDir = _getOriginalBackendLocation()

    shutil.copytree(defaultConfigDir, os.path.join(tempDir, 'etc', 'opsi'))

    yield BackendManager(backend=_serverBackend,
                         extensionconfigdir=os.path.join(
                             tempDir, 'etc', 'opsi', 'backendManager',
                             'extend.d'))
Ejemplo n.º 4
0
def getLocalDepot():
    """
	Get the local depot from the backend.

	:raises BackendConfigurationError: If no backend initialisation is possible.
	:raises BackendMissingDataError: If no depot is found.
	:return: The local depot.
	:rtype: OpsiDepotserver
	"""
    from OPSI.Backend.BackendManager import BackendManager

    try:
        with BackendManager() as backend:
            depot = backend.host_getObjects(type='OpsiDepotserver',
                                            id=getLocalFQDN())
            return depot[0]
    except IndexError:
        raise BackendMissingDataError("No depots found!")
    except Exception as err:
        LOGGER.warning("Has the backend been initialized?")
        raise BackendConfigurationError(
            "Unable to instantiate a backend: {}".format(err))
def testBackendManagerDispatchesCallsToExtensionClass():
    """
    Make sure that calls are dispatched to the extension class.
    These calls should not fail.
    """
    class TestClass(object):
        def methodOnBackend(self, y):
            assert y == 'yyyyyyyy'

        def checkIfOptionsExist(self):
            options = self.backend_getOptions()
            assert options

    cdb = ConfigDataBackend()
    bm = BackendManager(backend=cdb, extensionClass=TestClass)
    bm.methodOnBackend('yyyyyyyy')
    bm.checkIfOptionsExist()
Ejemplo n.º 6
0
#!/bin/python
# some functions grabbed from http://svn.opsi.org/opsi4.1/misc/time-driven-maintenance-tools/wake_clients_for_setup.py
from __future__ import print_function
from datetime import datetime
import os
import sys
import pprint
from OPSI.Logger import Logger, LOG_WARNING
from OPSI.Util.Ping import ping
import time

logger = Logger()
from OPSI.Backend.BackendManager import BackendManager
backending = BackendManager()


def getClientIDsFromGroup(backend, groupName):
    group = backend.group_getObjects(id=groupName, type="HostGroup")
    try:
        group = group[0]
    except IndexError:
        raise ValueError("No HostGroup with id '{0}' found!".format(groupName))
    return [
        mapping.objectId
        for mapping in backend.objectToGroup_getObjects(groupId=group.id)
    ]


def wakeClient(backend, clientId):
    logger.info("Waking {}", clientId)
    backend.hostControlSafe_start(clientId)
Ejemplo n.º 7
0
def editConfigDefaults():
    bmconfig = dict(
        dispatchConfigFile=u'/etc/opsi/backendManager/dispatch.conf',
        backendConfigDir=u'/etc/opsi/backends',
        extensionConfigDir=u'/etc/opsi/backendManager/extend.d',
        depotbackend=False)

    with BackendManager(**bmconfig) as backend:
        configs = backend.config_getObjects()
        configs = [
            config for config in configs
            if not config.id.startswith(u'configed.saved_search.')
        ]

        if not configs:
            raise BackendMissingDataError("Backend misses configurations!")

        maxConfigIdLen = max(len(config.id) for config in configs)
        entryFormat = u"%-10s %-" + str(maxConfigIdLen) + "s = %s"

        with disableConsoleLogging(), _getUI() as ui:
            while True:
                entries = []
                for config in configs:
                    configType = '[unicode]'
                    if config.getType() == 'BoolConfig':
                        configType = '[bool]'

                    values = u', '.join(forceUnicodeList(config.defaultValues))
                    values = shortenStr(values, 60)
                    entries.append({
                        "id":
                        config.id,
                        "name":
                        entryFormat % (configType, config.id, values)
                    })

                selection = ui.getSelection(
                    entries,
                    radio=True,
                    width=100,
                    height=10,
                    title=u'Please select config value to change',
                    okLabel='Change',
                    cancelLabel='Quit')

                if not selection:
                    return

                configId = None
                for entry in entries:
                    if selection[0] == entry['name']:
                        configId = entry['id']
                        break

                selectedConfig = -1
                for index, config in enumerate(configs):
                    if config.id == configId:
                        selectedConfig = index
                        break

                addNewValue = False
                cancelLabel = u'Back'
                title = u'Edit default values for: %s' % configs[
                    selectedConfig].id
                text = configs[selectedConfig].description or u''
                if configs[selectedConfig].possibleValues:
                    entries = []
                    for possibleValue in configs[
                            selectedConfig].possibleValues:
                        entries.append({
                            'name':
                            possibleValue,
                            'value':
                            possibleValue,
                            'selected':
                            possibleValue
                            in configs[selectedConfig].defaultValues
                        })
                    radio = not configs[selectedConfig].multiValue
                    if configs[selectedConfig].editable:
                        entries.append({
                            'name': '<other value>',
                            'value': '<other value>',
                            'selected': False
                        })
                    selection = ui.getSelection(entries,
                                                radio=radio,
                                                width=65,
                                                height=10,
                                                title=title,
                                                text=text,
                                                cancelLabel=cancelLabel)

                    if selection is None:
                        continue
                    if "<other value>" in selection:
                        addNewValue = True
                    else:
                        configs[selectedConfig].setDefaultValues(selection)
                else:
                    addNewValue = True

                if addNewValue:
                    default = u''
                    if configs[selectedConfig].defaultValues:
                        default = configs[selectedConfig].defaultValues[0]
                    value = ui.getValue(width=65,
                                        height=13,
                                        title=title,
                                        default=default,
                                        password=False,
                                        text=text,
                                        cancelLabel=cancelLabel)
                    if value is None:
                        continue

                    possibleValues = configs[selectedConfig].getPossibleValues(
                    )
                    if value not in possibleValues:
                        possibleValues.append(value)
                        configs[selectedConfig].setPossibleValues(
                            possibleValues)
                    configs[selectedConfig].setDefaultValues(value)

                backend.config_updateObjects([configs[selectedConfig]])
Ejemplo n.º 8
0
def cleanupBackend(backend=None):
    """
	Clean up data from your backends.

	This method uses different cleanup methods to ensure that no
	obsolete data is present in your backend.

	:param backend: the backend to check. If ``None`` this will create a \
BackendManager from default paths.
	:type backend: OPSI.Backend.Backend
	"""
    def usesMysqlBackend():
        LOGGER.notice(u"Parsing dispatch.conf")
        bdc = BackendDispatchConfigFile(
            u'/etc/opsi/backendManager/dispatch.conf')
        dispatchConfig = bdc.parse()
        for entry in dispatchConfig:
            (regex, backends) = entry
            if not re.search(regex, u'backend_createBase'):
                continue

            if 'mysql' in backends:
                return True

        return False

    LOGGER.debug("Cleaning backend chunk size: {0}".format(_CHUNK_SIZE))

    if backend is None:
        backend = BackendManager(
            dispatchConfigFile=u'/etc/opsi/backendManager/dispatch.conf',
            backendConfigDir=u'/etc/opsi/backends',
            extensionConfigDir=u'/etc/opsi/backendManager/extend.d',
            depotbackend=False)

        try:
            if usesMysqlBackend():
                LOGGER.notice(
                    u"Mysql-backend detected. Trying to cleanup mysql-backend first"
                )
                # ToDo: backendConfigFile should be as dynamic as possible
                # What if we have 2 mysql backends set up?
                cleanUpMySQL()
        except Exception as error:
            LOGGER.warning(error)

    LOGGER.notice(u"Cleaning up groups")
    cleanUpGroups(backend)

    LOGGER.notice(u"Cleaning up products")
    cleanUpProducts(backend)

    LOGGER.debug(u'Getting current depots...')
    depotIds = set(depot.id for depot in backend.host_getObjects(
        type=["OpsiConfigserver", "OpsiDepotserver"]))  # pylint: disable=maybe-no-member
    LOGGER.debug(u'Depots are: {0}'.format(depotIds))

    LOGGER.debug(u'Getting current products...')
    productIdents = set(
        product.getIdent(returnType='unicode')
        for product in backend.product_getObjects())
    LOGGER.debug(u'Product idents are: {0}'.format(productIdents))

    LOGGER.notice(u"Cleaning up product on depots")
    cleanUpProductOnDepots(backend, depotIds, productIdents)

    LOGGER.notice(u"Cleaning up product on clients")
    cleanUpProductOnClients(backend)

    LOGGER.notice(u"Cleaning up product properties")
    productPropertyIdents = set()
    deleteProductProperties = []
    productPropertiesToCleanup = {}
    for productProperty in backend.productProperty_getObjects():  # pylint: disable=maybe-no-member
        productIdent = u"%s;%s;%s" % (productProperty.productId,
                                      productProperty.productVersion,
                                      productProperty.packageVersion)
        if not productProperty.editable and productProperty.possibleValues:
            productPropertyIdent = u"%s;%s" % (productIdent,
                                               productProperty.propertyId)
            productPropertiesToCleanup[productPropertyIdent] = productProperty

        if productIdent not in productIdents:
            LOGGER.info(
                u"Marking productProperty %s of non existent product '%s' for deletion"
                % (productProperty, productIdent))
            deleteProductProperties.append(productProperty)
        else:
            productPropertyIdent = u'%s;%s' % (productProperty.productId,
                                               productProperty.propertyId)
            productPropertyIdents.add(productPropertyIdent)

    if deleteProductProperties:
        for productProperties in chunk(deleteProductProperties, _CHUNK_SIZE):
            LOGGER.debug(u"Deleting product properties: {0!r}".format(
                productProperties))
            backend.productProperty_deleteObjects(productProperties)  # pylint: disable=maybe-no-member

    LOGGER.notice(u"Cleaning up product property states")
    deleteProductPropertyStates = []
    for productPropertyState in backend.productPropertyState_getObjects():  # pylint: disable=maybe-no-member
        productPropertyIdent = u'%s;%s' % (productPropertyState.productId,
                                           productPropertyState.propertyId)
        if productPropertyIdent not in productPropertyIdents:
            LOGGER.info(
                u"Marking productPropertyState %s of non existent productProperty '%s' for deletion"
                % (productPropertyState, productPropertyIdent))
            deleteProductPropertyStates.append(productPropertyState)

    if deleteProductPropertyStates:
        for productPropertyStates in chunk(deleteProductPropertyStates,
                                           _CHUNK_SIZE):
            LOGGER.debug(u"Deleting product property states: {0!r}".format(
                productPropertyStates))
            backend.productPropertyState_deleteObjects(productPropertyStates)  # pylint: disable=maybe-no-member

    for depot in backend.host_getObjects(type='OpsiDepotserver'):  # pylint: disable=maybe-no-member
        objectIds = set(
            ClientToDepot['clientId']
            for ClientToDepot in backend.configState_getClientToDepotserver(
                depotIds=depot.id))
        objectIds.add(depot.id)

        productOnDepotIdents = {}
        for productOnDepot in backend.productOnDepot_getObjects(
                depotId=depot.id):  # pylint: disable=maybe-no-member
            productIdent = u"%s;%s;%s" % (productOnDepot.productId,
                                          productOnDepot.productVersion,
                                          productOnDepot.packageVersion)
            productOnDepotIdents[productOnDepot.productId] = productIdent

        if not productOnDepotIdents:
            continue

        deleteProductPropertyStates = []
        updateProductPropertyStates = []
        for productPropertyState in backend.productPropertyState_getObjects(  # pylint: disable=maybe-no-member
                objectId=objectIds,
                productId=productOnDepotIdents.keys(),
                propertyId=[]):
            productIdent = productOnDepotIdents.get(
                productPropertyState.productId)
            if not productIdent:
                continue
            productPropertyIdent = u"%s;%s" % (productIdent,
                                               productPropertyState.propertyId)
            productProperty = productPropertiesToCleanup.get(
                productPropertyIdent)
            if not productProperty:
                continue
            changed = False
            newValues = []
            removeValues = []
            changedValues = []
            for value in productPropertyState.values:
                if value in productProperty.possibleValues:
                    newValues.append(value)
                    continue
                if productProperty.getType(
                ) == u'BoolProductProperty' and forceBool(
                        value) in productProperty.possibleValues:
                    newValues.append(forceBool(value))
                    changedValues.append(value)
                    changed = True
                    continue
                if productProperty.getType() == u'UnicodeProductProperty':
                    newValue = None
                    for possibleValue in productProperty.possibleValues:
                        if forceUnicodeLower(
                                possibleValue) == forceUnicodeLower(value):
                            newValue = possibleValue
                            break
                    if newValue:
                        newValues.append(newValue)
                        changedValues.append(value)
                        changed = True
                        continue
                removeValues.append(value)
                changed = True
            if changed:
                if not newValues:
                    LOGGER.info(
                        u"Marking productPropertyState %s for deletion: no value in possible values (%s)"
                        % (productPropertyState, removeValues))
                    deleteProductPropertyStates.append(productPropertyState)
                else:
                    productPropertyState.setValues(newValues)
                    LOGGER.info(
                        u"Marking productPropertyState %s for update: values not in possible values: %s, values corrected: %s"
                        % (productPropertyState, removeValues, changedValues))
                    updateProductPropertyStates.append(productPropertyState)

        if deleteProductPropertyStates:
            for productPropertyStates in chunk(deleteProductPropertyStates,
                                               _CHUNK_SIZE):
                LOGGER.debug(u"Deleting product property states: {0!r}".format(
                    productPropertyStates))
                backend.productPropertyState_deleteObjects(
                    productPropertyStates)  # pylint: disable=maybe-no-member
            del deleteProductPropertyStates

        if updateProductPropertyStates:
            for productPropertyStates in chunk(updateProductPropertyStates,
                                               _CHUNK_SIZE):
                LOGGER.debug(u"Updating product property states: {0!r}".format(
                    productPropertyStates))
                backend.productPropertyState_updateObjects(
                    productPropertyStates)  # pylint: disable=maybe-no-member
            del updateProductPropertyStates

    LOGGER.notice(u"Cleaning up config states")
    cleanUpConfigStates(backend)

    LOGGER.notice(u"Cleaning up audit softwares")
    cleanUpAuditSoftwares(backend)

    LOGGER.notice(u"Cleaning up audit software on clients")
    cleanUpAuditSoftwareOnClients(backend)
Ejemplo n.º 9
0
def initializeBackends(ipAddress=None):
	"""
	Initial backend setup based on the current configuration.

	This will create required folders aswell as set up the current
	backend for use with opsi.

	:param ipAddress: Force the function to work with the given IP address.
	:type ipAddress: str
	"""
	_setupPasswdFile()

	from OPSI.Backend.BackendManager import BackendManager

	managerConfig = {
		"dispatchConfigFile": u'/etc/opsi/backendManager/dispatch.conf',
		"backendConfigDir": u'/etc/opsi/backends',
		"extensionConfigDir": u'/etc/opsi/backendManager/extend.d',
		"depotbackend": False
	}

	with BackendManager(**managerConfig) as backend:
		backend.backend_createBase()

		networkConfig = getNetworkConfiguration(ipAddress)
		fqdn = getLocalFqdn()

		LOGGER.info(u"Trying to find a Configserver...")
		configServer = backend.host_getObjects(type='OpsiConfigserver')
		if not configServer and not backend.host_getIdents(type='OpsiConfigserver', id=fqdn):
			depot = backend.host_getObjects(type='OpsiDepotserver', id=fqdn)
			if not depot:
				LOGGER.notice(u"Creating config server '%s'" % fqdn)
				serverConfig = _getServerConfig(fqdn, networkConfig)
				backend.host_createOpsiConfigserver(**serverConfig)
				configServer = backend.host_getObjects(type='OpsiConfigserver', id=fqdn)
			else:
				LOGGER.notice(u"Converting depot server '%s' to config server" % fqdn)
				configServer = OpsiConfigserver.fromHash(depot[0].toHash())
				backend.host_createObjects(configServer)

				# list expected in further processing
				configServer = [configServer]
		else:
			depot = backend.host_getObjects(type='OpsiDepotserver', id=fqdn)
			if not depot:
				LOGGER.notice(u"Creating depot server '%s'" % fqdn)
				serverConfig = _getServerConfig(fqdn, networkConfig)
				backend.host_createOpsiDepotserver(**serverConfig)

		if configServer:
			if configServer[0].id == fqdn:
				try:
					configServer = backend.host_getObjects(type='OpsiConfigserver')[0]
				except IndexError:
					raise Exception(u"Config server '%s' not found" % fqdn)

				if networkConfig['ipAddress']:
					configServer.setIpAddress(networkConfig['ipAddress'])
				if networkConfig['hardwareAddress']:
					configServer.setHardwareAddress(networkConfig['hardwareAddress'])

				# make sure the config server is present in all backends or we get reference error later on
				backend.host_insertObject(configServer)

			# initializeConfigs does only handle a single object
			configServer = forceList(configServer)[0]

		initializeConfigs(backend=backend, configServer=configServer)

	_setupDepotDirectory()
	_setupWorkbenchDirectory()