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()
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_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))
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
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
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)
def get(cls, computer): from aiida.backends.djsite.db.models import DbComputer return cls(dbcomputer=DbComputer.get_dbcomputer(computer))
def _set_db_computer(self, computer): from aiida.backends.djsite.db.models import DbComputer self.dbnode.dbcomputer = DbComputer.get_dbcomputer(computer)
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()