Ejemplo n.º 1
0
 def get_aiida_class(self):
     from aiida.backends.djsite.db.models import DbComputer as DjangoSchemaDbComputer
     djcomputer = DjangoSchemaDbComputer(
         id=self.id,
         uuid=self.uuid,
         name=self.name,
         hostname=self.hostname,
         description=self.description,
         enabled=self.enabled,
         transport_type=self.transport_type,
         scheduler_type=self.scheduler_type,
         transport_params=self.transport_params,
         metadata=self._metadata)
     return djcomputer.get_aiida_class()
Ejemplo n.º 2
0
    def __init__(self, **kwargs):
        super(Computer, self).__init__()

        uuid = kwargs.pop('uuid', None)
        if uuid is not None:
            if kwargs:
                raise ValueError("If you pass a uuid, you cannot pass any "
                                 "further parameter")
            try:
                dbcomputer = DbComputer.objects.get(uuid=uuid)
            except ObjectDoesNotExist:
                raise NotExistent("No entry with UUID={} found".format(uuid))

            self._dbcomputer = dbcomputer
        else:
            if 'dbcomputer' in kwargs:
                dbcomputer = kwargs.pop('dbcomputer')
                if not (isinstance(dbcomputer, DbComputer)):
                    raise TypeError("dbcomputer must be of type DbComputer")
                self._dbcomputer = dbcomputer

                if kwargs:
                    raise ValueError("If you pass a dbcomputer parameter, "
                                     "you cannot pass any further parameter")
            else:
                self._dbcomputer = DbComputer()

            # Set all remaining parameters, stop if unknown
            self.set(**kwargs)
Ejemplo n.º 3
0
 def set_computer(self, computer):
     from aiida.backends.djsite.db.models import DbComputer
     if self._to_be_stored:
         self.dbnode.dbcomputer = DbComputer.get_dbcomputer(computer)
     else:
         raise ModificationNotAllowed(
             "Node with uuid={} was already stored".format(self.uuid))
Ejemplo n.º 4
0
def get_dbauthinfo(computer, aiidauser):
    """
    Given a computer and a user, returns a DbAuthInfo object

    :param computer: a computer (can be a string, Computer or DbComputer instance)
    :param aiidauser: a user, can be a DbUser or a User instance
    :return: a DbAuthInfo instance
    :raise NotExistent: if the user is not configured to use computer
    :raise sqlalchemy.orm.exc.MultipleResultsFound: if the user is configured 
         more than once to use the computer! Should never happen
    """
    from aiida.common.exceptions import InternalError
    if settings.BACKEND == BACKEND_DJANGO:
        from aiida.backends.djsite.db.models import DbComputer, DbAuthInfo, DbUser
        from django.core.exceptions import (ObjectDoesNotExist,
                                            MultipleObjectsReturned)

        try:
            authinfo = DbAuthInfo.objects.get(
                # converts from name, Computer or DbComputer instance to
                # a DbComputer instance
                dbcomputer=DbComputer.get_dbcomputer(computer),
                aiidauser=aiidauser.id)
        except ObjectDoesNotExist:
            raise NotExistent(
                "The aiida user {} is not configured to use computer {}".
                format(aiidauser.email, computer.name))
        except MultipleObjectsReturned:
            raise ConfigurationError(
                "The aiida user {} is configured more than once to use "
                "computer {}! Only one configuration is allowed".format(
                    aiidauser.email, computer.name))
    elif settings.BACKEND == BACKEND_SQLA:

        from aiida.backends.sqlalchemy.models.authinfo import DbAuthInfo
        from aiida.backends.sqlalchemy import get_scoped_session
        session = get_scoped_session()
        from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound

        try:
            authinfo = session.query(DbAuthInfo).filter_by(
                dbcomputer_id=computer.id,
                aiidauser_id=aiidauser.id,
            ).one()
        except NoResultFound:
            raise NotExistent(
                "The aiida user {} is not configured to use computer {}".
                format(aiidauser.email, computer.name))
        except MultipleResultsFound:
            raise ConfigurationError(
                "The aiida user {} is configured more than once to use "
                "computer {}! Only one configuration is allowed".format(
                    aiidauser.email, computer.name))

    else:
        raise InternalError("unknown backend {}".format(settings.BACKEND))
    return authinfo
Ejemplo n.º 5
0
def get_authinfo(computer, aiidauser):

    if settings.BACKEND == BACKEND_DJANGO:
        from aiida.backends.djsite.db.models import DbComputer, DbAuthInfo
        from django.core.exceptions import (ObjectDoesNotExist,
                                            MultipleObjectsReturned)

        try:
            authinfo = DbAuthInfo.objects.get(
                # converts from name, Computer or DbComputer instance to
                # a DbComputer instance
                dbcomputer=DbComputer.get_dbcomputer(computer),
                aiidauser=aiidauser)
        except ObjectDoesNotExist:
            raise AuthenticationError(
                "The aiida user {} is not configured to use computer {}".
                format(aiidauser.email, computer.name))
        except MultipleObjectsReturned:
            raise ConfigurationError(
                "The aiida user {} is configured more than once to use "
                "computer {}! Only one configuration is allowed".format(
                    aiidauser.email, computer.name))
    elif settings.BACKEND == BACKEND_SQLA:
        from aiida.backends.sqlalchemy.models.authinfo import DbAuthInfo
        from aiida.backends.sqlalchemy import get_scoped_session
        session = get_scoped_session()
        from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
        try:
            authinfo = session.query(DbAuthInfo).filter_by(
                dbcomputer_id=computer.id,
                aiidauser_id=aiidauser.id,
            ).one()
        except NoResultFound:
            raise AuthenticationError(
                "The aiida user {} is not configured to use computer {}".
                format(aiidauser.email, computer.name))
        except MultipleResultsFound:
            raise ConfigurationError(
                "The aiida user {} is configured more than once to use "
                "computer {}! Only one configuration is allowed".format(
                    aiidauser.email, computer.name))

    else:
        raise Exception("unknown backend {}".format(settings.BACKEND))
    return authinfo
Ejemplo n.º 6
0
    def can_run_on(self, computer):
        """
        Return True if this code can run on the given computer, False otherwise.

        Local codes can run on any machine; remote codes can run only on the machine
        on which they reside.

        TODO: add filters to mask the remote machines on which a local code can run.
        """
        from aiida.backends.djsite.db.models import DbComputer
        if self.is_local():
            return True
        else:
            dbcomputer = computer
            if isinstance(dbcomputer, Computer):
                dbcomputer = dbcomputer.dbcomputer
            if not isinstance(dbcomputer, DbComputer):
                raise ValueError(
                    "computer must be either a Computer or DbComputer object")
            dbcomputer = DbComputer.get_dbcomputer(computer)
            return (dbcomputer.pk == self.get_remote_computer().dbcomputer.pk)
Ejemplo n.º 7
0
 def get(cls, computer):
     from aiida.backends.djsite.db.models import DbComputer
     return cls(dbcomputer=DbComputer.get_dbcomputer(computer))
Ejemplo n.º 8
0
 def _set_db_computer(self, computer):
     from aiida.backends.djsite.db.models import DbComputer
     self.dbnode.dbcomputer = DbComputer.get_dbcomputer(computer)
Ejemplo n.º 9
0
class Computer(AbstractComputer):
    @property
    def uuid(self):
        return unicode(self._dbcomputer.uuid)

    @property
    def pk(self):
        return self.dbcomputer.pk

    @property
    def id(self):
        return self.dbcomputer.pk

    def __init__(self, **kwargs):
        super(Computer, self).__init__()

        uuid = kwargs.pop('uuid', None)
        if uuid is not None:
            if kwargs:
                raise ValueError("If you pass a uuid, you cannot pass any "
                                 "further parameter")
            try:
                dbcomputer = DbComputer.objects.get(uuid=uuid)
            except ObjectDoesNotExist:
                raise NotExistent("No entry with UUID={} found".format(uuid))

            self._dbcomputer = dbcomputer
        else:
            if 'dbcomputer' in kwargs:
                dbcomputer = kwargs.pop('dbcomputer')
                if not (isinstance(dbcomputer, DbComputer)):
                    raise TypeError("dbcomputer must be of type DbComputer")
                self._dbcomputer = dbcomputer

                if kwargs:
                    raise ValueError("If you pass a dbcomputer parameter, "
                                     "you cannot pass any further parameter")
            else:
                self._dbcomputer = DbComputer()

            # Set all remaining parameters, stop if unknown
            self.set(**kwargs)

    def set(self, **kwargs):
        for k, v in kwargs.iteritems():
            try:
                method = getattr(self, 'set_{}'.format(k))
            except AttributeError:
                raise ValueError("Unable to set '{0}', no set_{0} method "
                                 "found".format(k))
            if not isinstance(method, collections.Callable):
                raise ValueError("Unable to set '{0}', set_{0} is not "
                                 "callable!".format(k))
            method(v)

    @classmethod
    def list_names(cls):
        from aiida.backends.djsite.db.models import DbComputer
        return list(DbComputer.objects.filter().values_list('name', flat=True))

    @property
    def full_text_info(self):
        ret_lines = []
        ret_lines.append("Computer name:     {}".format(self.name))
        ret_lines.append(" * PK:             {}".format(self.pk))
        ret_lines.append(" * UUID:           {}".format(self.uuid))
        ret_lines.append(" * Description:    {}".format(self.description))
        ret_lines.append(" * Hostname:       {}".format(self.hostname))
        ret_lines.append(" * Enabled:        {}".format(
            "True" if self.is_enabled() else "False"))
        ret_lines.append(" * Transport type: {}".format(
            self.get_transport_type()))
        ret_lines.append(" * Scheduler type: {}".format(
            self.get_scheduler_type()))
        ret_lines.append(" * Work directory: {}".format(self.get_workdir()))
        ret_lines.append(" * Shebang:        {}".format(self.get_shebang()))
        ret_lines.append(" * mpirun command: {}".format(" ".join(
            self.get_mpirun_command())))
        def_cpus_machine = self.get_default_mpiprocs_per_machine()
        if def_cpus_machine is not None:
            ret_lines.append(
                " * Default number of cpus per machine: {}".format(
                    def_cpus_machine))
        ret_lines.append(" * Used by:        {} nodes".format(
            len(self.dbcomputer.dbnodes.all())))

        ret_lines.append(" * prepend text:")
        if self.get_prepend_text().strip():
            for l in self.get_prepend_text().split('\n'):
                ret_lines.append("   {}".format(l))
        else:
            ret_lines.append("   # No prepend text.")
        ret_lines.append(" * append text:")
        if self.get_append_text().strip():
            for l in self.get_append_text().split('\n'):
                ret_lines.append("   {}".format(l))
        else:
            ret_lines.append("   # No append text.")

        return "\n".join(ret_lines)

    @property
    def to_be_stored(self):
        return (self._dbcomputer.pk is None)

    @classmethod
    def get(cls, computer):
        from aiida.backends.djsite.db.models import DbComputer
        return cls(dbcomputer=DbComputer.get_dbcomputer(computer))

    def copy(self):
        from aiida.backends.djsite.db.models import DbComputer
        if self.to_be_stored:
            raise InvalidOperation(
                "You can copy a computer only after having stored it")
        newdbcomputer = DbComputer.objects.get(pk=self.pk)
        newdbcomputer.pk = None

        newobject = self.__class__(dbcomputer=newdbcomputer)

        return newobject

    @property
    def dbcomputer(self):
        """
        Return the DbComputer. If already saved, reloads it from the DB.

        :return: Return the DbComputer
        """
        if self._dbcomputer.pk:
            self._dbcomputer = DbComputer.objects.get(pk=self._dbcomputer.pk)

        return self._dbcomputer

    def store(self):
        # if self.to_be_stored:

        # As a first thing, I check if the data is valid
        self.validate()
        try:
            # transactions are needed here for Postgresql:
            # https://docs.djangoproject.com/en/1.5/topics/db/transactions/#handling-exceptions-within-postgresql-transactions
            sid = transaction.savepoint()
            self._dbcomputer.save()
            transaction.savepoint_commit(sid)
        except IntegrityError:
            transaction.savepoint_rollback(sid)
            raise ValueError(
                "Integrity error, probably the hostname already exists in the"
                " DB")

        # This is useful because in this way I can do
        # c = Computer().store()
        return self

    @property
    def name(self):
        return self.dbcomputer.name

    @property
    def description(self):
        return self.dbcomputer.description

    @property
    def hostname(self):
        return self.dbcomputer.hostname

    def _get_metadata(self):
        return json.loads(self.dbcomputer.metadata)

    def _set_metadata(self, metadata_dict):
        # When setting, use the uncached _dbcomputer

        # if not self.to_be_stored:
        #            raise ModificationNotAllowed("Cannot set a property after having stored the entry")
        self._dbcomputer.metadata = json.dumps(metadata_dict)
        if not self.to_be_stored:
            self._dbcomputer.save()

    def get_transport_params(self):
        try:
            return json.loads(self.dbcomputer.transport_params)
        except ValueError:
            raise DbContentError(
                "Error while reading transport_params for computer {}".format(
                    self.hostname))

    def set_transport_params(self, val):
        # When setting, use the uncached _dbcomputer

        # if self.to_be_stored:
        try:
            self._dbcomputer.transport_params = json.dumps(val)
        except ValueError:
            raise ValueError("The set of transport_params are not JSON-able")
        if not self.to_be_stored:
            self._dbcomputer.save()

    def get_workdir(self):
        try:
            return self.dbcomputer.get_workdir()
        except ConfigurationError:
            # This happens the first time: I provide a reasonable default value
            return "/scratch/{username}/aiida_run/"

    def get_shebang(self):
        try:
            return self.dbcomputer.get_shebang()
        except ConfigurationError:
            # This happens the first time: I provide a reasonable default value
            return "#!/bin/bash"

    def set_workdir(self, val):
        # if self.to_be_stored:
        if not isinstance(val, basestring):
            raise ValueError(
                "Computer work directory needs to be string, got {}".format(
                    val))

        metadata = self._get_metadata()
        metadata['workdir'] = val
        self._set_metadata(metadata)

    def get_name(self):
        return self.dbcomputer.name

    def set_name(self, val):
        # When setting, use the uncached _dbcomputer
        self._dbcomputer.name = val
        if not self.to_be_stored:
            self._dbcomputer.save()

    def get_hostname(self):
        return self.dbcomputer.hostname

    def set_hostname(self, val):
        # When setting, use the uncached _dbcomputer
        self._dbcomputer.hostname = val
        if not self.to_be_stored:
            self._dbcomputer.save()

    def get_description(self):
        return self.dbcomputer.description

    def set_description(self, val):
        # When setting, use the uncached _dbcomputer
        self._dbcomputer.description = val
        if not self.to_be_stored:
            self._dbcomputer.save()

    def get_calculations_on_computer(self):
        from aiida.backends.djsite.db.models import DbNode
        return DbNode.objects.filter(dbcomputer__name=self.name,
                                     type__startswith='calculation')

    def is_enabled(self):
        return self.dbcomputer.enabled

    def set_enabled_state(self, enabled):
        """
        Set the enabled state.

        :param enabled: the new state
        """
        # When setting, use the uncached _dbcomputer
        self._dbcomputer.enabled = enabled
        if not self.to_be_stored:
            self._dbcomputer.save()

    def get_scheduler_type(self):
        return self.dbcomputer.scheduler_type

    def set_scheduler_type(self, val):
        # When setting, use the uncached _dbcomputer
        self._dbcomputer.scheduler_type = val
        if not self.to_be_stored:
            self._dbcomputer.save()

    def get_transport_type(self):
        return self.dbcomputer.transport_type

    def set_transport_type(self, val):
        # When setting, use the uncached _dbcomputer
        self._dbcomputer.transport_type = val
        if not self.to_be_stored:
            self._dbcomputer.save()