Esempio n. 1
0
class InstanceGroup(ndb.Model):
    """Datastore representation of a GCE instance group.

  Key:
    InstanceGroup is a root entity.
    id: Hash of the instance group name.
  """
    # rpc_messages.Dimensions describing members of this instance group.
    dimensions = msgprop.MessageProperty(rpc_messages.Dimensions,
                                         required=True)
    # Names of members of this instance group.
    members = ndb.LocalStructuredProperty(Instance, repeated=True)
    # Name of this instance group.
    name = ndb.StringProperty(required=True)
    # rpc_messages.Policies governing members of this instance group.
    policies = msgprop.MessageProperty(rpc_messages.Policies, required=True)
    # Name of the project this instance group exists in.
    project = ndb.StringProperty(required=True)
    # Zone the members of this instance group exist in. e.g. us-central1-f.
    zone = ndb.StringProperty(required=True)

    @classmethod
    def generate_key(cls, name):
        """Generates the key for an InstanceGroup with the given name.

    Args:
      name: Name of this instance group.

    Returns:
      An ndb.Key instance.
    """
        return ndb.Key(cls, hashlib.sha1(name).hexdigest())
Esempio n. 2
0
class InstanceGroup(ndb.Model):
    """Datastore representation of a GCE instance group.

  Key:
    Instance group is a root entity.
    id: Hash of the instance group name.
  """
    # rpc_messages.Dimensions describing members of this instance group.
    dimensions = msgprop.MessageProperty(rpc_messages.Dimensions,
                                         required=True)
    # Names of members of this instance group.
    members = ndb.StringProperty(repeated=True)
    # Name of this instance group.
    name = ndb.StringProperty(required=True)
    # rpc_messages.Policies governing members of this instance group.
    policies = msgprop.MessageProperty(rpc_messages.Policies, required=True)

    @classmethod
    def create_and_put(cls, name, dimensions, policies, members):
        """Creates a new InstanceGroup entity and puts it in the datastore.

    Args:
      name: Name of this instance group.
      dimensions: rpc_messages.Dimensions describing members of this instance
        group.
      policies: rpc_messages.Policies governing members of this instance group.
      members: A list of names of members of this instance group.
    """
        assert dimensions.backend == rpc_messages.Backend.GCE
        cls(
            key=cls.generate_key(name),
            dimensions=dimensions,
            members=members,
            name=name,
            policies=policies,
        ).put()

    @classmethod
    def generate_key(cls, name):
        """Generates the key for an InstanceGroup with the given name.

    Args:
      name: Name of this instance group.

    Returns:
      An ndb.Key instance.
    """
        return ndb.Key(cls, hashlib.sha1(name).hexdigest())
Esempio n. 3
0
class MachineType(ndb.Model):
    """A type of machine which should be leased from the Machine Provider.

  Key:
    id: A human-readable name for this machine type.
    kind: MachineType. Is a root entity.
  """
    # Current number of active leases.
    current_size = ndb.ComputedProperty(lambda self: len(self.leases))
    # Description of this machine type for humans.
    description = ndb.StringProperty(indexed=False)
    # Whether or not to attempt to lease machines of this type.
    enabled = ndb.BooleanProperty(default=True)
    # Duration to lease each machine for.
    lease_duration_secs = ndb.IntegerProperty(indexed=False)
    # List of active lease requests.
    leases = ndb.LocalStructuredProperty(MachineLease, repeated=True)
    # machine_provider.Dimensions describing the machine.
    mp_dimensions = msgprop.MessageProperty(machine_provider.Dimensions,
                                            indexed=False)
    # Number of bots pending deletion.
    num_pending_deletion = ndb.ComputedProperty(
        lambda self: len(self.pending_deletion))
    # List of hostnames whose leases have expired and should be deleted.
    pending_deletion = ndb.StringProperty(indexed=False, repeated=True)
    # Last request number used.
    request_count = ndb.IntegerProperty(default=0, required=True)
    # Request ID base string.
    request_id_base = ndb.StringProperty(indexed=False, required=True)
    # Target number of machines of this type to have leased at once.
    target_size = ndb.IntegerProperty(indexed=False, required=True)
Esempio n. 4
0
class InstanceTemplateRevision(ndb.Model):
    """A specific revision of an instance template in the config.

  Key:
    id: Checksum of the instance template config.
    kind: InstanceTemplate.
  """
    # List of ndb.Keys for the InstanceGroupManagers.
    active = ndb.KeyProperty(kind=InstanceGroupManager, repeated=True)
    # rpc_messages.Dimensions describing instances created from this template.
    dimensions = msgprop.MessageProperty(rpc_messages.Dimensions)
    # Disk size in GiB for instances created from this template.
    disk_size_gb = ndb.IntegerProperty(indexed=False)
    # List of ndb.Keys for drained InstanceGroupManagers.
    drained = ndb.KeyProperty(kind=InstanceGroupManager, repeated=True)
    # Name of the image for instances created from this template.
    image_name = ndb.StringProperty(indexed=False)
    # GCE machine type for instances created from this template.
    machine_type = ndb.StringProperty(indexed=False)
    # Initial metadata to apply when creating instances from this template.
    metadata = ndb.JsonProperty()
    # Project to create the instance template in.
    project = ndb.StringProperty(indexed=False)
    # List of service accounts available to instances created from this template.
    service_accounts = ndb.LocalStructuredProperty(ServiceAccount,
                                                   repeated=True)
    # Initial list of tags to apply when creating instances from this template.
    tags = ndb.StringProperty(indexed=False, repeated=True)
    # URL of the instance template created from this entity.
    url = ndb.StringProperty(indexed=False)
Esempio n. 5
0
class MachineLease(ndb.Model):
    """A lease request for a machine from the Machine Provider.

  Key:
    id: A string in the form <machine type id>-<number>.
    kind: MachineLease. Is a root entity.
  """
    # Request ID used to generate this request.
    client_request_id = ndb.StringProperty(indexed=True)
    # Whether or not this MachineLease should issue lease requests.
    drained = ndb.BooleanProperty(indexed=True)
    # Number of seconds ahead of lease_expiration_ts to release leases.
    early_release_secs = ndb.IntegerProperty(indexed=False)
    # Hostname of the machine currently allocated for this request.
    hostname = ndb.StringProperty()
    # Duration to lease for.
    lease_duration_secs = ndb.IntegerProperty(indexed=False)
    # DateTime indicating lease expiration time.
    lease_expiration_ts = ndb.DateTimeProperty()
    # Lease ID assigned by Machine Provider.
    lease_id = ndb.StringProperty(indexed=False)
    # ndb.Key for the MachineType this MachineLease is created for.
    machine_type = ndb.KeyProperty()
    # machine_provider.Dimensions describing the machine.
    mp_dimensions = msgprop.MessageProperty(machine_provider.Dimensions,
                                            indexed=False)
    # Last request number used.
    request_count = ndb.IntegerProperty(default=0, required=True)
    # Task ID for the termination task scheduled for this machine.
    termination_task = ndb.StringProperty(indexed=False)
Esempio n. 6
0
class CatalogEntry(ndb.Model):
    """Datastore representation of an entry in the catalog."""
    # rpc_messages.Dimensions describing this machine.
    dimensions = msgprop.MessageProperty(
        rpc_messages.Dimensions,
        indexed_fields=[
            field.name for field in rpc_messages.Dimensions.all_fields()
        ],
    )
Esempio n. 7
0
class Instruction(ndb.Model):
    """Datastore representation of an instruction for a machine.

  Standalone instances should not be present in the datastore.
  """
    # Instruction to execute.
    instruction = msgprop.MessageProperty(rpc_messages.Instruction)
    # State of the instruction.
    state = ndb.StringProperty(choices=InstructionStates)
Esempio n. 8
0
class CatalogEntry(ndb.Model):
    """Datastore representation of an entry in the catalog."""
    # rpc_messages.Dimensions describing this machine.
    dimensions = msgprop.MessageProperty(
        rpc_messages.Dimensions,
        indexed_fields=[
            field.name for field in rpc_messages.Dimensions.all_fields()
        ],
    )
    # DateTime indicating the last modified time.
    last_modified_ts = ndb.DateTimeProperty(auto_now=True)
Esempio n. 9
0
class MachineType(ndb.Model):
    """A type of machine which should be leased from the Machine Provider.

  Key:
    id: A human-readable name for this machine type.
    kind: MachineType. Is a root entity.
  """
    # Description of this machine type for humans.
    description = ndb.StringProperty(indexed=False)
    # Number of seconds ahead of lease_expiration_ts to release leases.
    early_release_secs = ndb.IntegerProperty(indexed=False)
    # Whether or not to attempt to lease machines of this type.
    enabled = ndb.BooleanProperty(default=True)
    # Duration to lease each machine for.
    lease_duration_secs = ndb.IntegerProperty(indexed=False)
    # machine_provider.Dimensions describing the machine.
    mp_dimensions = msgprop.MessageProperty(machine_provider.Dimensions,
                                            indexed=False)
    # Target number of machines of this type to have leased at once.
    target_size = ndb.IntegerProperty(indexed=False, required=True)
Esempio n. 10
0
class InstanceTemplateRevision(ndb.Model):
    """A specific revision of an instance template in the config.

  Key:
    id: Checksum of the instance template config.
    parent: InstanceTemplate.
  """
    # List of ndb.Keys for the InstanceGroupManagers.
    active = ndb.KeyProperty(kind=InstanceGroupManager, repeated=True)
    # Enable external network with automatic IP assignment.
    auto_assign_external_ip = ndb.BooleanProperty(indexed=False)
    # rpc_messages.Dimensions describing instances created from this template.
    dimensions = msgprop.MessageProperty(rpc_messages.Dimensions)
    # Disk size in GiB for instances created from this template.
    disk_size_gb = ndb.IntegerProperty(indexed=False)
    # Disk type for instances created from this template.
    disk_type = ndb.StringProperty(indexed=False)
    # List of ndb.Keys for drained InstanceGroupManagers.
    drained = ndb.KeyProperty(kind=InstanceGroupManager, repeated=True)
    # Name of the image for instances created from this template.
    image_name = ndb.StringProperty(indexed=False)
    # Project containing the image specified by image_name.
    image_project = ndb.StringProperty(indexed=False)
    # GCE machine type for instances created from this template.
    machine_type = ndb.StringProperty(indexed=False)
    # Initial metadata to apply when creating instances from this template.
    metadata = ndb.JsonProperty()
    # Minimum CPU platform for instances created from this template.
    min_cpu_platform = ndb.StringProperty(indexed=False)
    # Network URL for this template.
    network_url = ndb.StringProperty(indexed=False)
    # Project to create the instance template in.
    project = ndb.StringProperty(indexed=False)
    # List of service accounts available to instances created from this template.
    service_accounts = ndb.LocalStructuredProperty(ServiceAccount,
                                                   repeated=True)
    # Initial list of tags to apply when creating instances from this template.
    tags = ndb.StringProperty(indexed=False, repeated=True)
    # URL of the instance template created from this entity.
    url = ndb.StringProperty(indexed=False)
Esempio n. 11
0
class PlacesStore(ndb.Model):
    places = msgprop.MessageProperty(
        Places,
        indexed_fields=['places.name', 'places.latitude', 'places.longitude'])
Esempio n. 12
0
class PersistentUser(ndb.Model):
    email = ndb.StringProperty()
    domain = ndb.StringProperty()
    created = ndb.DateTimeProperty(auto_now_add=True)
    modified = ndb.DateTimeProperty(auto_now=True)
    modified_by = ndb.StringProperty()
    created_by = ndb.StringProperty()
    num_folders = ndb.IntegerProperty()
    is_wildcard = ndb.BooleanProperty()
    folders = msgprop.MessageProperty(FolderMessage, repeated=True)
    folder_status = msgprop.EnumProperty(FolderStatus)
    questions = msgprop.MessageProperty(QuestionMessage, repeated=True)
    reason = ndb.TextProperty()

    def _pre_put_hook(self):
        if self.email:
            self.email = self.email.strip().lower()
            self.domain = self.email.split('@')[-1]
            self.is_wildcard = self.email[0] == '*'
        if self.created_by:
            self.created_by = self.created_by.strip().lower()
        if self.modified_by:
            self.modified_by = self.modified_by.strip().lower()
        if self.folders:
            folder_status = FolderStatus.ALL_APPROVED
            for folder in self.folders:
                if folder.has_requested:
                    folder_status = FolderStatus.SOME_REQUESTED
            self.folder_status = folder_status
            self.num_folders = len(
                [folder for folder in self.folders if folder.has_access])

    @classmethod
    def search(cls, query_string=None, cursor=None, limit=None):
        limit = limit or 200
        start_cursor = datastore_query.Cursor(urlsafe=cursor) \
                if cursor else None
        query = cls.query()
        if query_string:
            # TODO: Support query language.
            query = query.filter(cls.email == query_string)
        query = query.order(-cls.created)
        results, next_cursor, has_more = \
                query.fetch_page(limit, start_cursor=start_cursor)
        return (results, next_cursor, has_more)

    @classmethod
    def normalize_email(cls, email):
        return email.strip().lower().replace(' ', '')

    def can_read(self, path_from_url):
        # When FOLDERS have changed after the user was added.
        # This should be moved to when PersistentUser is instantiated.
        self.folders = self.normalize_folders()
        for folder in self.folders:
            path_regex = folder.regex
            if re.match(path_regex, path_from_url):
                if not folder.has_access:
                    return False
        return True

    def normalize_folders(self):
        ids_to_folders = {}
        all_folders = list_folder_messages()
        for folder in all_folders:
            ids_to_folders[folder.folder_id] = folder
        for folder in self.folders:
            # Old folder no longer used.
            if folder.folder_id not in ids_to_folders:
                continue
            ids_to_folders[folder.folder_id].has_access = folder.has_access
            ids_to_folders[
                folder.folder_id].has_requested = folder.has_requested
        all_folders = ids_to_folders.values()
        return sorted(all_folders, key=lambda folder: folder.title)

    @classmethod
    def import_from_sheets(cls,
                           sheet_id,
                           sheet_gid,
                           folders=None,
                           created_by=None):
        rows = google_sheets.get_sheet(sheet_id, gid=sheet_gid)
        emails = [row['email'] for row in rows]
        if not folders:
            folders = list_folder_messages(default_has_access=True)
        return cls.create_or_update_multi(emails,
                                          folders=folders,
                                          created_by=created_by)

    @classmethod
    def to_csv(cls):
        # TODO: Move to separate file.
        from protorpc import protojson
        import io
        import csv
        import json
        _csv_header = [
            'created',
            'email',
            'folders',
        ]
        header = _csv_header
        ents, _, _ = cls.search(limit=5000)
        rows = []
        for ent in ents:
            row = json.loads(protojson.encode_message(ent.to_message()))
            for key in row.keys():
                if key not in header:
                    del row[key]
            for key in row:
                if key == 'folders':
                    row[key] = json.dumps(row[key])
                if isinstance(row[key], unicode):
                    row[key] = row[key].encode('utf-8')
            rows.append(row)
        if not rows:
            return ''
        fp = io.BytesIO()
        writer = csv.DictWriter(fp, header)
        writer.writeheader()
        writer.writerows(rows)
        fp.seek(0)
        return fp.read()

    @classmethod
    def create(cls, email, folders=None, created_by=None):
        user = cls._create(email, folders, created_by)
        user.put()
        return user

    @classmethod
    def _create(cls, email, folders=None, created_by=None):
        email = cls.normalize_email(email)
        key = ndb.Key('PersistentUser', email)
        user = cls(key=key)
        user.email = email
        if folders:
            user.folders = folders
        else:
            user.folders = list_folder_messages()
        user.created_by = created_by
        user.modified_by = created_by
        return user

    def add_folders(self, folders):
        ids_to_folders = {}
        for folder in self.normalize_folders():
            ids_to_folders[folder.folder_id] = folder
        for folder in folders:
            if folder.has_access and folder.folder_id in ids_to_folders:
                ids_to_folders[folder.folder_id].has_access = True
        all_folders = ids_to_folders.values()
        all_folders = sorted(all_folders, key=lambda folder: folder.title)
        self.folders = all_folders

    @classmethod
    def create_or_update_multi(cls, emails, folders=None, created_by=None):
        keys = [
            ndb.Key('PersistentUser', cls.normalize_email(email))
            for email in emails if email
        ]
        ents = ndb.get_multi(keys)
        for i, ent in enumerate(ents):
            if not ent:
                ents[i] = cls._create(emails[i],
                                      folders=folders,
                                      created_by=created_by)
                continue
            ent.add_folders(folders)
        ndb.put_multi(ents)
        return ents

    @classmethod
    def create_multi(cls, emails, folders=None, created_by=None):
        ents = [
            cls._create(email, folders=folders, created_by=created_by)
            for email in emails
        ]
        ndb.put_multi(ents)
        return ents

    @classmethod
    def get(cls, email):
        email = cls.normalize_email(email)
        key = ndb.Key('PersistentUser', email)
        return key.get()

    @classmethod
    def get_by_email(cls, email):
        email = cls.normalize_email(email)
        key = ndb.Key('PersistentUser', email)
        return key.get()

    @classmethod
    def get_or_create(cls, email):
        ent = cls.get(email)
        return ent or cls.create(email)

    def delete(self):
        self.key.delete()

    def to_message(self):
        message = UserMessage()
        message.created_by = self.created_by
        message.modified_by = self.modified_by
        message.created = self.created
        message.domain = self.domain
        message.email = self.email
        if self.folders:
            message.folders = self.normalize_folders()
        message.folder_status = self.folder_status
        message.modified = self.modified
        message.num_folders = self.num_folders
        if self.questions:
            message.questions = self.questions
        if self.reason:
            message.reason = self.reason
        return message

    def request_access(self,
                       folders,
                       questions=None,
                       reason=None,
                       send_notification=False):
        if questions:
            self.questions = questions
        if reason:
            self.reason = reason
        all_folders = self.normalize_folders()
        requested_folder_ids = [folder.folder_id for folder in folders]
        for i, folder in enumerate(all_folders):
            is_requested = folder.folder_id in requested_folder_ids
            # Set newly-requested folders while leaving previously requested
            # folders as-is.
            if is_requested:
                all_folders[i].has_requested = is_requested
        self.folders = all_folders
        self.put()
        if send_notification:
            build_server_config = config.instance()
            email_config = build_server_config['access_requests']['emails']
            req = {
                'email': self.email,
                'form': questions,
            }
            from . import access_requests
            access_requests.send_email_to_admins(req,
                                                 email_config=email_config)

    def update_folders(self, folders, updated_by=None):
        self.folders = folders
        if updated_by:
            self.updated_by = updated_by
        self.put()
Esempio n. 13
0
class Game(ndb.Model):
    """ Google AppEngine Datastore Entity representing a Battleship match.

    Properties:
        player_one: ndb Key to the player that hosted the game.
        player_two: ndb Key to the player that joined the game.
        game_state: GameState representing the state of the game.
        game_settings: The BoardRules set for the game at creation.
        game_board: JsonProperty that holds the players' ship positions.
            A dictionary in the form:
            {
                'player_one': [{ship list}]
                'player_two': [{ship list}]
            }
                ship_list: A list of all the ships in the players fleet.
                    A ship is a list of string representations of each
                    coordinate that the ship occupies.
        game_history: JsonProperty that holds the history of players' guesses.
            A python list of each guess in the form:
                [{user_name},{coords},{result}]
                    user_name: string of the name of user who made guess
                    coords: string in form 'x,y' of user's guess
                    result: string result of the guess. Typically hit or miss.
        player_winner: ndb Key to the winner of the match.
        last_update: A datetime of the last time the game was updated.
    """
    class GameState(messages.Enum):
        """ Enum for representing the different states of the game. """
        # Game has just been created and is waiting for second player.
        WAITING_FOR_OPPONENT = 0
        # Second player has just joined the game. Waiting for ship placements.
        PREPARING_BOARD = 1
        # Waiting for player one to guess.
        PLAYER_ONE_TURN = 2
        # Waiting for player two to guess.
        PLAYER_TWO_TURN = 3
        # A player has sunk all their opponent's ships.
        GAME_COMPLETE = 4
        # A player has cancelled the game.
        GAME_CANCELLED = 5

    class BoardRules(messages.Message):
        """ Message that describes the rules of a game.

        Properties:
            width: The width of the game board. Must be between 8-20.
            height: The height of the game board. Must be between 8-20.
            ship_2: The number of ships of length 2. Must be between 0-5.
            ship_3: The number of ships of length 3. Must be between 0-5.
            ship_4: The number of ships of length 4. Must be between 0-5.
            ship_5: The number of ships of length 5. Must be between 0-5.
        """
        width = messages.IntegerField(1, default=10)
        height = messages.IntegerField(2, default=10)
        ship_2 = messages.IntegerField(3, default=1)
        ship_3 = messages.IntegerField(4, default=2)
        ship_4 = messages.IntegerField(5, default=1)
        ship_5 = messages.IntegerField(6, default=1)

    player_one = ndb.KeyProperty(required=True, kind='User')
    player_two = ndb.KeyProperty(kind='User')
    game_state = msgprop.EnumProperty(GameState, required=True)
    game_settings = msgprop.MessageProperty(BoardRules, required=True)
    game_board = ndb.JsonProperty()
    game_history = ndb.JsonProperty()
    player_winner = ndb.KeyProperty(kind='User')
    last_update = ndb.DateTimeProperty(auto_now=True)

    @classmethod
    def create_game(cls, user, form):
        """ Creates a new Game.

        Args:
            user: User that is creating the game
            form: NewGameForm containing the game's rules

        Returns:
            Returns the newly created Game.
        """

        settings = form.get_assigned_value('rules') or cls.BoardRules()

        # Fix an issue with default values not saving until assigned.
        settings.width = settings.width
        settings.height = settings.height
        settings.ship_2 = settings.ship_2
        settings.ship_3 = settings.ship_3
        settings.ship_4 = settings.ship_4
        settings.ship_5 = settings.ship_5

        # Check that rules are valid
        if (settings.width < 8 or settings.width > 20 or settings.height < 8
                or settings.height > 20):
            raise endpoints.BadRequestException(
                'Board dimensions must be between 8-20')
        if (settings.ship_2 < 0 or settings.ship_2 > 5 or settings.ship_3 < 0
                or settings.ship_3 > 5 or settings.ship_4 < 0
                or settings.ship_4 > 5 or settings.ship_5 < 0
                or settings.ship_5 > 5):
            raise endpoints.BadRequestException(
                'Ship count must be between 0-5')
        game = Game(player_one=user.key,
                    game_state=cls.GameState.WAITING_FOR_OPPONENT,
                    game_settings=settings,
                    game_board={},
                    game_history=[])
        game.put()
        return game

    @classmethod
    def by_urlsafe(cls, urlsafe):
        """ Search for a game by its urlsafe key """
        try:
            return ndb.Key(urlsafe=urlsafe).get()
        except TypeError:
            raise endpoints.BadRequestException('Invalid Key')
        except Exception, e:
            if e.__class__.__name__ == 'ProtocolBufferDecodeError':
                raise endpoints.BadRequestException('Invalid Key')
            else:
                raise
Esempio n. 14
0
class LeaseRequest(ndb.Model):
    """Datastore representation of a LeaseRequest.

  Key:
    id: Hash of the client + client-generated request ID which issued the
      original rpc_messages.LeaseRequest instance. Used for easy deduplication.
    kind: LeaseRequest. This root entity does not reference any parents.
  """
    # DateTime indicating original datastore write time.
    created_ts = ndb.DateTimeProperty(auto_now_add=True)
    # Checksum of the rpc_messages.LeaseRequest instance. Used to compare incoming
    # LeaseRequets for deduplication.
    deduplication_checksum = ndb.StringProperty(required=True, indexed=False)
    # ID of the CatalogMachineEntry provided for this lease.
    machine_id = ndb.StringProperty()
    # auth.model.Identity of the issuer of the original request.
    owner = auth.IdentityProperty(required=True)
    # Element of LeaseRequestStates giving the state of this request.
    state = ndb.StringProperty(choices=LeaseRequestStates, required=True)
    # rpc_messages.LeaseRequest instance representing the original request.
    request = msgprop.MessageProperty(rpc_messages.LeaseRequest, required=True)
    # rpc_messages.LeaseResponse instance representing the current response.
    # This field will be updated as the request is being processed.
    response = msgprop.MessageProperty(rpc_messages.LeaseResponse)

    @classmethod
    def compute_deduplication_checksum(cls, request):
        """Computes the deduplication checksum for the given request.

    Args:
      request: The rpc_messages.LeaseRequest instance to deduplicate.

    Returns:
      The deduplication checksum.
    """
        return hashlib.sha1(protobuf.encode_message(request)).hexdigest()

    @classmethod
    def generate_key(cls, user, request):
        """Generates the key for the given request initiated by the given user.

    Args:
      user: An auth.model.Identity instance representing the requester.
      request: The rpc_messages.LeaseRequest sent by the user.

    Returns:
      An ndb.Key instance.
    """
        # Enforces per-user request ID uniqueness
        return ndb.Key(
            cls,
            hashlib.sha1('%s\0%s' % (user, request.request_id)).hexdigest(),
        )

    @classmethod
    def query_untriaged(cls):
        """Queries for untriaged LeaseRequests.

    Yields:
      Untriaged LeaseRequests in no guaranteed order.
    """
        for request in cls.query(cls.state == LeaseRequestStates.UNTRIAGED):
            yield request
Esempio n. 15
0
class CatalogMachineEntry(CatalogEntry):
    """Datastore representation of a machine in the catalog.

  Key:
    id: Hash of the backend + hostname dimensions. Used to enforce per-backend
      hostname uniqueness.
    kind: CatalogMachineEntry. This root entity does not reference any parents.
  """
    # ID of the LeaseRequest this machine is provided for.
    lease_id = ndb.StringProperty()
    # DateTime indicating lease expiration time.
    lease_expiration_ts = ndb.DateTimeProperty()
    # rpc_messages.Policies governing this machine.
    policies = msgprop.MessageProperty(rpc_messages.Policies)
    # Element of CatalogMachineEntryStates giving the state of this entry.
    state = ndb.StringProperty(
        choices=CatalogMachineEntryStates,
        default=CatalogMachineEntryStates.AVAILABLE,
        indexed=True,
        required=True,
    )

    @classmethod
    def create_and_put(cls, dimensions, policies, state):
        """Creates a new CatalogEntry entity and puts it in the datastore.

    Args:
      dimensions: rpc_messages.Dimensions describing this machine.
      policies: rpc_messages.Policies governing this machine.
      state: Element of CatalogMachineEntryState describing this machine.
    """
        cls(
            dimensions=dimensions,
            policies=policies,
            state=state,
            key=cls.generate_key(dimensions),
        ).put()

    @classmethod
    def generate_key(cls, dimensions):
        """Generates the key for a CatalogEntry with the given dimensions.

    Args:
      dimensions: rpc_messages.Dimensions describing this machine.

    Returns:
      An ndb.Key instance.
    """
        # Enforces per-backend hostname uniqueness.
        assert dimensions.backend is not None
        assert dimensions.hostname is not None
        return ndb.Key(
            cls,
            hashlib.sha1(
                '%s\0%s' %
                (dimensions.backend, dimensions.hostname)).hexdigest(),
        )

    @classmethod
    def query_available(cls, *filters):
        """Queries for available machines.

    Args:
      *filters: Any additional filters to include in the query.

    Yields:
      CatalogMachineEntry keys in no guaranteed order.
    """
        available = cls.state == CatalogMachineEntryStates.AVAILABLE
        for machine in cls.query(available, *filters).fetch(keys_only=True):
            yield machine
Esempio n. 16
0
class Leaderboard(ndb.Model):
    leaderboard = msgprop.MessageProperty(Leaderboard_m)
Esempio n. 17
0
class NoteStore(ndb.Model):
    note = msgprop.MessageProperty(Note, indexed_fields=['when'])
    name = ndb.StringProperty()
Esempio n. 18
0
class CatalogMachineEntry(CatalogEntry):
    """Datastore representation of a machine in the catalog.

  Key:
    id: Hash of the backend + hostname dimensions. Used to enforce per-backend
      hostname uniqueness.
    kind: CatalogMachineEntry. This root entity does not reference any parents.
  """
    # Instruction for this machine.
    instruction = ndb.LocalStructuredProperty(Instruction)
    # ID of the LeaseRequest this machine is provided for.
    lease_id = ndb.StringProperty()
    # DateTime indicating lease expiration time.
    lease_expiration_ts = ndb.DateTimeProperty()
    # rpc_messages.Policies governing this machine.
    policies = msgprop.MessageProperty(rpc_messages.Policies)
    # Determines sorted order relative to other CatalogMachineEntries.
    sort_ordering = ndb.ComputedProperty(lambda self: '%s:%s' % (
        self.dimensions.backend, self.dimensions.hostname))
    # Element of CatalogMachineEntryStates giving the state of this entry.
    state = ndb.StringProperty(
        choices=CatalogMachineEntryStates,
        default=CatalogMachineEntryStates.AVAILABLE,
        indexed=True,
        required=True,
    )

    @classmethod
    def generate_key(cls, dimensions):
        """Generates the key for a CatalogEntry with the given dimensions.

    Args:
      dimensions: rpc_messages.Dimensions describing this machine.

    Returns:
      An ndb.Key instance.
    """
        # Enforces per-backend hostname uniqueness.
        assert dimensions.backend is not None
        assert dimensions.hostname is not None
        return cls._generate_key(dimensions.backend, dimensions.hostname)

    @classmethod
    def _generate_key(cls, backend, hostname):
        """Generates the key for a CatalogEntry with the given backend and hostname.

    Args:
      backend: rpc_messages.Backend.
      hostname: Hostname of the machine.

    Returns:
      An ndb.Key instance.
    """
        return ndb.Key(
            cls,
            hashlib.sha1('%s\0%s' % (backend, hostname)).hexdigest(),
        )

    @classmethod
    def get(cls, backend, hostname):
        """Gets the CatalogEntry with by backend and hostname.

    Args:
      backend: rpc_messages.Backend.
      hostname: Hostname of the machine.

    Returns:
      An ndb.Key instance.
    """
        return cls._generate_key(backend, hostname).get()

    @classmethod
    def query_available(cls, *filters):
        """Queries for available machines.

    Args:
      *filters: Any additional filters to include in the query.

    Yields:
      CatalogMachineEntry keys in no guaranteed order.
    """
        available = cls.state == CatalogMachineEntryStates.AVAILABLE
        for machine in cls.query(available, *filters).fetch(keys_only=True):
            yield machine
Esempio n. 19
0
class SignedStorableNotebook(ndb.Model):
    author = ndb.StringProperty()
    nb = msgprop.MessageProperty(Notebook,
                                 indexed_fields=['notes.text', 'notes.when'])